-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from websitesieutoc/move-next-template-to-tubor
Move next template to tubor
- Loading branch information
Showing
182 changed files
with
10,608 additions
and
215 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
ARGON_SECRET=topsecret | ||
NEXTAUTH_SECRET=topsecret | ||
NEXTAUTH_URL=http://localhost:3000 | ||
|
||
KV_REST_API_URL= | ||
KV_REST_API_TOKEN= | ||
|
||
# NOTE: The DB/USER/PASSWORD need to be the same with docker-compose values | ||
POSTGRES_DB=postgres | ||
POSTGRES_USER=postgres | ||
POSTGRES_PASSWORD=password | ||
POSTGRES_URL_NON_POOLING="${POSTGRES_URL}" | ||
POSTGRES_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?schema=public" | ||
POSTGRES_PRISMA_URL="${POSTGRES_URL}?pgbouncer=true&connect_timeout=15" | ||
|
||
NEXT_PUBLIC_API_KEY_TINYMCE="" | ||
|
||
EMAIL_SERVER_USER= # your email | ||
EMAIL_SERVER_PASSWORD= # your password | ||
EMAIL_SERVER_HOST= #smtp.gmail.com | ||
EMAIL_SERVER_PORT= #465 | ||
SENDGRID_API_KEY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module.exports = { | ||
root: true, | ||
extends: ['sieutoc'], | ||
rules: { | ||
'no-plusplus': 'off', | ||
'no-underscore-dangle': 'off', | ||
'react/display-name': 'off', | ||
'@typescript-eslint/explicit-function-return-type': 'off', | ||
'@typescript-eslint/explicit-module-boundary-types': 'off', | ||
'@typescript-eslint/interface-name-prefix': 'off', | ||
'@typescript-eslint/no-explicit-any': 'off', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env.local | ||
.env | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"$schema": "http://json.schemastore.org/prettierrc", | ||
"overrides": [ | ||
{ | ||
"files": ["*.yaml", "*.json"], | ||
"options": { | ||
"singleQuote": false | ||
} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"options": { | ||
"printWidth": 80, | ||
"singleQuote": true, | ||
"trailingComma": "es5" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). | ||
|
||
## Features | ||
|
||
This template includes the following: | ||
|
||
- Next.js 13 | ||
- TypeScript | ||
- ESLint | ||
- Prettier | ||
- Chakra UI | ||
- Prisma | ||
- Next-Auth | ||
- Docker Compose with: | ||
- PostgresQL | ||
- Redis | ||
- Mailpit | ||
|
||
## Demo | ||
|
||
https://nextjs-template-demo.vercel.app | ||
|
||
|
||
## Getting Started | ||
|
||
#### For Development | ||
|
||
- We use `pnpm` package manager. Get it [here](https://pnpm.io/installation). | ||
- Make sure Docker up and running. | ||
- If your Docker account has 2FA enabled, you have to create a Personal Access Token and login before: | ||
- Follow [this guide](https://docs.docker.com/docker-hub/access-tokens/). | ||
- Login with `docker login --username <your-username>` | ||
|
||
#### Clone the project | ||
|
||
You can either use this template by: | ||
|
||
- Click the **"Use this template"** button and follow the instruction | ||
- Or using the script below: | ||
|
||
```bash | ||
npx tiged websitesieutoc/nextjs-template your-project | ||
``` | ||
|
||
Then, search and replace `nextjs-template` with your project slug. | ||
|
||
#### Install dependencies | ||
|
||
```bash | ||
cd your-project | ||
pnpm install | ||
``` | ||
|
||
#### Setup environment variables | ||
|
||
For the first time, you need some default environment variables: | ||
|
||
```bash | ||
cp .env.example .env | ||
``` | ||
|
||
Then, run the development server: | ||
|
||
```bash | ||
pnpm dev | ||
``` | ||
|
||
Open [http://localhost:3000](http://localhost:3000) with your browser and start developing. | ||
|
||
## Good to know | ||
|
||
- This project uses `App Router` feature. | ||
- We try to take adventage of Next.js's ecosystem, thus most of the features here are built on top of Next.js best practices. | ||
- We use Chakra UI as our primary library. For ready-made themes, please find it at our [themes](https://github.com/websitesieutoc/themes) repo. | ||
- In the future we will launch a tool for customising your own themes soon! | ||
|
||
#### Why do not use <headless-cms-name> here? | ||
|
||
- We're fully aware of the headless CMS system. | ||
- But there are ton of boilerplats out there, which already do a great jobs, so we do not want to re-invent them. | ||
- Most of them are really tightly coupled with the headless CMS API, so customers always end up to hack around a lot. | ||
- We need only a lite version of CMS, nothing else. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
'use client'; // Error components must be Client Components | ||
|
||
import { Box, useToast } from '@/components/chakra'; | ||
import { ErrorBoundary } from '@/components/client'; | ||
import { useEffect } from 'react'; | ||
|
||
export default function Error({ | ||
error, | ||
reset, | ||
}: { | ||
error: Error; | ||
reset: () => void; | ||
}) { | ||
const toast = useToast(); | ||
useEffect(() => { | ||
// Log the error to an error reporting service | ||
toast({ | ||
status: 'error', | ||
title: error.name, | ||
description: error.message, | ||
}); | ||
}, [error, toast]); | ||
|
||
return ( | ||
<Box textAlign="center"> | ||
<ErrorBoundary error={error} reset={reset} /> | ||
</Box> | ||
); | ||
} |
49 changes: 49 additions & 0 deletions
49
apps/dashboard/app/[locale]/(auth)/forgot-password/ForgotPasswordForm/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
'use client'; | ||
|
||
import { useRouter, useState } from '@/hooks'; | ||
import { Input, Button, Box, Code } from '@/components/chakra'; | ||
import { FormWrapper } from '@/components/client'; | ||
import { HttpMethod } from '@/types'; | ||
import { fetcher } from '@/utils/fetcher'; | ||
|
||
export const ForgotPasswordForm = () => { | ||
const [error, setError] = useState(''); | ||
const router = useRouter(); | ||
|
||
const handleAction = async (formData: FormData) => { | ||
setError(''); | ||
const { email } = Object.fromEntries(formData.entries()) as { | ||
email: string; | ||
}; | ||
if (!email || !email.trim()) return alert('Please enter email address!'); | ||
|
||
const request = await fetcher<{ | ||
data?: { email: string }; | ||
status: number; | ||
message: string; | ||
}>(`/api/users/password`, { | ||
method: HttpMethod.POST, | ||
body: JSON.stringify({ | ||
email: email, | ||
}), | ||
}); | ||
|
||
if (request?.data?.email) { | ||
router.push( | ||
`/forgot-password/update-password?email=${request.data.email}` | ||
); | ||
} else { | ||
setError(request.message); | ||
} | ||
}; | ||
|
||
return ( | ||
<FormWrapper action={handleAction}> | ||
<Input autoFocus name="email" type="email" isRequired /> | ||
{error && <Code color="red">{error}</Code>} | ||
<Button width="100%" marginTop={3} type="submit" size="lg"> | ||
Continue | ||
</Button> | ||
</FormWrapper> | ||
); | ||
}; |
39 changes: 39 additions & 0 deletions
39
apps/dashboard/app/[locale]/(auth)/forgot-password/confirm-email/Status/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
'use client'; | ||
|
||
import { redirect } from 'next/navigation'; | ||
import { Box, Icon, Stack } from '@/components/chakra'; | ||
import { CheckCircleIcon, WarningTwoIcon } from '@/icons'; | ||
import { User } from '@/types'; | ||
import { useEffect, useRouter } from '@/hooks'; | ||
|
||
type StatusPropTypes = { | ||
isTimeOver: boolean; | ||
result: { | ||
data?: Omit<User, 'password'>; | ||
status: number; | ||
description: string; | ||
}; | ||
}; | ||
export const Status = ({ result, isTimeOver }: StatusPropTypes) => { | ||
const router = useRouter(); | ||
useEffect(() => { | ||
if (!result || isTimeOver) { | ||
router.push('/forgot-password/confirm-email'); | ||
} | ||
setTimeout(() => redirect('/'), 5_000); | ||
}, [result, isTimeOver, router]); | ||
|
||
return ( | ||
<Stack | ||
color={result?.status === 200 ? 'green.400' : 'red.400'} | ||
direction="row" | ||
spacing={1} | ||
> | ||
<Icon | ||
as={result?.status === 200 ? CheckCircleIcon : WarningTwoIcon} | ||
boxSize={6} | ||
/> | ||
<Box>{result?.description}</Box> | ||
</Stack> | ||
); | ||
}; |
18 changes: 18 additions & 0 deletions
18
apps/dashboard/app/[locale]/(auth)/forgot-password/confirm-email/loading.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Container, Skeleton, Stack } from '@/components/chakra'; | ||
|
||
export default function ConfirmEmailLoading() { | ||
return ( | ||
<Stack spacing={8} maxWidth="md" marginX="auto" paddingTop="10vh"> | ||
<Container shadow="base" rounded={10} paddingX={10} padding={10}> | ||
<Stack padding={3} spacing={1} maxW={650} justify="center"> | ||
<Skeleton height="40px" rounded={5} width="150px" marginBottom={4} /> | ||
|
||
<Skeleton height="40px" rounded={5} /> | ||
<Skeleton height="40px" rounded={5} /> | ||
<Skeleton height="40px" rounded={5} /> | ||
<Skeleton height="40px" rounded={5} /> | ||
</Stack> | ||
</Container> | ||
</Stack> | ||
); | ||
} |
49 changes: 49 additions & 0 deletions
49
apps/dashboard/app/[locale]/(auth)/forgot-password/confirm-email/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { redirect } from 'next/navigation'; | ||
import { Stack } from '@/components/chakra'; | ||
import { Container } from '@/components/chakra'; | ||
import { Locale } from '@/types'; | ||
import { differenceInHours } from 'date-fns'; | ||
import { Status } from './Status'; | ||
import { verifyResetPassword } from '@/services/users'; | ||
import { HOUR_MAX_CONFIRM } from '@/utils/constants'; | ||
|
||
type ConfirmResetPassFromEmailType = { | ||
params: { locale: Locale }; | ||
searchParams: { code: string }; | ||
}; | ||
export default async function ConfirmResetPassFromEmail( | ||
props: ConfirmResetPassFromEmailType | ||
) { | ||
const { code } = props.searchParams; | ||
const items = code?.split(':'); | ||
|
||
if (items?.length !== 4) { | ||
redirect('/'); | ||
} | ||
|
||
const dateTimeSubmit = Number(items?.[0]); | ||
const confirmCode = items?.[0] + ':' + items?.[1]; | ||
const newPassword = items?.[2]?.replace(/ /g, '+'); | ||
|
||
const email = items?.[3]; | ||
const now = Date.now(); | ||
const timeDifference = differenceInHours(now, dateTimeSubmit); | ||
const isTimeOver = timeDifference >= HOUR_MAX_CONFIRM; | ||
const data = isTimeOver | ||
? { | ||
data: undefined, | ||
status: 404, | ||
description: 'Time limit expired', | ||
} | ||
: await verifyResetPassword(email, newPassword, confirmCode); | ||
|
||
return ( | ||
<Stack spacing={8} maxWidth="md" marginX="auto" paddingTop="10vh"> | ||
<Container shadow="base" rounded={10} paddingX={10} padding={10}> | ||
<Stack padding={3} spacing={1} maxW={650} justify="center"> | ||
<Status isTimeOver={isTimeOver} result={data} /> | ||
</Stack> | ||
</Container> | ||
</Stack> | ||
); | ||
} |
Oops, something went wrong.