Skip to content

Commit

Permalink
Merge pull request #68 from websitesieutoc/big-migration-on-schema
Browse files Browse the repository at this point in the history
change massive from Site to Project
  • Loading branch information
sangdth authored Dec 4, 2023
2 parents b434e37 + 6fdf71a commit 0c7c5f6
Show file tree
Hide file tree
Showing 83 changed files with 2,520 additions and 1,267 deletions.
35 changes: 18 additions & 17 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
NEXTAUTH_SECRET=topsecret
ARGON_SECRET=topsecret

# Mandatory next-auth URL for localhost
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=topsecret

# For Docker
# --- Start for development
POSTGRES_PORT=5433
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=password
# --- End for development

# PostgreSQL database URL – get one here: https://vercel.com/docs/storage/vercel-postgres/quickstart
# PostgreSQL database URL
DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public"

# Vercel Blob Storage for image uploads – currently in beta, please fill out this form for access: https://tally.so/r/nPDMNd. Setup instructions: https://vercel.com/docs/storage/vercel-blob/quickstart
BLOB_READ_WRITE_TOKEN=asfdasdf
# Use this one for Github Oauth and syncing
# GITHUB_TOKEN=
# GITHUB_ID=
# GITHUB_SECRET=
# GITHUB_ORG=

# GitHub OAuth secrets for auth & login – generate these here: https://github-client-generator.vercel.app/
GITHUB_ID=
GITHUB_SECRET=
# Use this one for magic link authentication
SMTP_USER=mailpit
SMTP_PASSWORD=topsecret
SMTP_HOST=0.0.0.0
SMTP_PORT=1025
EMAIL_FROM=[email protected]

# Vercel authentication token that can be found here: https://vercel.com/account/tokens
VERCEL_TOKEN=
# Vercel Team ID that can be found here: https://vercel.com/teams/<org>/settings
TEAM_ID_VERCEL=
EASYPANEL_API_KEY=
EASYPANEL_URL=

# OpenAI API key for AI text generation – get one here: https://platform.openai.com/account/api-keys
OPENAI_API_KEY=
STRIPE_SECRET_KEY=
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<a href="https://sieutoc.website">
<img alt="Sieutoc" src="/public/thumbnail.png">
<h1 align="center">Website Sieutoc</h1>
<h1 align="center">Sieutoc</h1>
</a>

<p align="center">
Create modern website sieu toc!
Create modern apps in minutes
</p>

<br/>
Expand Down
99 changes: 99 additions & 0 deletions app/(auth)/login/components/LoginByEmail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
'use client';

import {
useEffect,
useKeyPressEvent,
useSearchParams,
useState,
useToast,
} from '@/hooks';
import {
Alert,
AlertDescription,
AlertIcon,
AlertTitle,
Box,
Button,
Input,
Stack,
} from '@/components/chakra';
import { signIn } from 'next-auth/react';
import { FlashIcon } from '@/icons';

export type LoginByEmailProps = {
isRequested: boolean;
};

export const LoginByEmail = ({ isRequested }: LoginByEmailProps) => {
const toast = useToast();
const [isFocused, setFocused] = useState(false);
const [isLoading, setLoading] = useState(false);

// Get error message added by next/auth in URL.
const searchParams = useSearchParams();
const error = searchParams?.get('error');

const [email, setEmail] = useState('');

const handleSignIn = async () => {
const callbackUrl = searchParams?.get('callbackUrl') ?? '/';

setLoading(true);

await signIn('email', {
email,
callbackUrl,
});
};

useEffect(() => {
const errorMessage = Array.isArray(error) ? error.pop() : error;
errorMessage && toast({ description: errorMessage, status: 'error' });
}, [error, toast]);

useKeyPressEvent('Enter', (e) => {
if (isFocused && email && !isLoading) {
e.preventDefault();
handleSignIn();
}
});

return (
<Stack gap={4}>
{isRequested && (
<Alert status="success" variant="subtle" borderRadius="md" pb={4}>
<AlertIcon boxSize="20px" />
<Box>
<AlertTitle mt={2}>Check your email!</AlertTitle>
<AlertDescription fontSize="sm">
We sent an email to you with a magic link that will sign you in. You can
close this window.
</AlertDescription>
</Box>
</Alert>
)}

<Input
size="lg"
value={email}
borderWidth="2px"
focusBorderColor="brand.500"
placeholder="[email protected]"
onFocus={() => setFocused(true)}
onBlur={() => setFocused(false)}
onChange={(e) => setEmail(e.target.value)}
/>

<Button
size="lg"
colorScheme="brand"
isLoading={isLoading}
isDisabled={isLoading || !email}
leftIcon={<FlashIcon />}
onClick={handleSignIn}
>
Login with Email
</Button>
</Stack>
);
};
62 changes: 62 additions & 0 deletions app/(auth)/login/components/LoginByGithub.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import { useState, useEffect, useSearchParams, useToast } from '@/hooks';
import { Button, Stack, Text } from '@/components/chakra';
import { signIn } from 'next-auth/react';
import { GithubIcon } from '@/icons';

export type LoginByGithubProps = {
org?: string;
};

export const LoginByGithub = ({ org }: LoginByGithubProps) => {
const toast = useToast();
const [isLoading, setLoading] = useState(false);

// Get error message added by next/auth in URL.
const searchParams = useSearchParams();
const error = searchParams?.get('error');

useEffect(() => {
const errorMessage = Array.isArray(error) ? error.pop() : error;
errorMessage && toast({ description: errorMessage, status: 'error' });
}, [error, toast]);

const getCallbackUrl = () => {
const callbackUrl = searchParams?.get('callbackUrl');

if (typeof callbackUrl === 'string') {
return callbackUrl;
}

return '/';
};

return (
<Stack gap={1} textAlign="center">
<Button
size="lg"
colorScheme="brand"
isLoading={isLoading}
isDisabled={isLoading}
leftIcon={<GithubIcon />}
loadingText="Login with GitHub"
onClick={() => {
setLoading(true);
signIn('github', {
redirect: true,
callbackUrl: getCallbackUrl(),
});
}}
>
Login with GitHub
</Button>

{org && (
<Text fontSize="small" color="gray">
Only for members of @{org} at this time.
</Text>
)}
</Stack>
);
};
2 changes: 2 additions & 0 deletions app/(auth)/login/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './LoginByGithub';
export * from './LoginByEmail';
50 changes: 0 additions & 50 deletions app/(auth)/login/login-button.tsx

This file was deleted.

33 changes: 26 additions & 7 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import { Divider, Heading, Stack, Text } from '@/components/chakra';
import { Divider, Heading, Stack } from '@/components/chakra';
import { Logo } from '@/components/client';
import { redirect } from 'next/navigation';
import { getSession } from '@/lib/auth';
import { cookies } from 'next/headers';

import LoginButton from './login-button';
import { LoginByEmail, LoginByGithub } from './components';

const hasGithubProvider = !!process.env.GITHUB_ID && !!process.env.GITHUB_SECRET;
const hasEmailProvider = !!process.env.SMTP_USER && !!process.env.SMTP_PASSWORD;

export default async function LoginPage() {
const session = await getSession();

if (session) {
redirect('/projects');
}

const cookieStore = cookies();
const requestCookie = cookieStore.get('verificationRequest');
const isRequested = !!requestCookie && requestCookie.value === 'true';

export default function LoginPage() {
return (
<Stack gap={4} maxWidth="sm" marginX="auto" marginTop="10vh">
<Logo width={256} height={74} />
Expand All @@ -14,11 +30,14 @@ export default function LoginPage() {

<Divider />

<LoginButton />
{hasEmailProvider && <LoginByEmail isRequested={isRequested} />}

<Text fontSize="small" color="gray">
Only for members of @websitesieutoc at this time.
</Text>
{hasGithubProvider && (
<>
<Divider />
<LoginByGithub org={process.env.GITHUB_ORG} />
</>
)}
</Stack>
);
}
Loading

0 comments on commit 0c7c5f6

Please sign in to comment.