Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rec #667

Merged
merged 7 commits into from
Mar 11, 2024
Merged

Rec #667

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .prettierignore

This file was deleted.

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ With this template, you get all the awesomeness you need:
- [Internationalization](#internationalization)
- [Client-side](#client-side)
- [Server side](#server-side)
- [Loading optimization](#loading-optimization)
- [Traduction file](#traduction-file)
- [🤝 Contribution](#-contribution)
- [Support](#support)
Expand Down Expand Up @@ -278,6 +279,10 @@ export default async function Home({
}
```

#### Loading optimization

The dictionary is loaded on the server and passed on the client only on the first load. If you make any changes to the dictionary, the server will see the difference and send the new dictionary to the client.

#### Traduction file

The files for traduction are located in `packages/app/src/langs` or `packages/landing/src/langs` depending on the package you want to use it in.
Expand Down
64 changes: 5 additions & 59 deletions apps/app/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,11 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require("path")
const { join } = require("path")

/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: [
"next",
"prettier",
"react-app/jest",
"plugin:@typescript-eslint/recommended",
"plugin:tailwindcss/recommended",
],
parser: "@typescript-eslint/parser",
root: true,
parserOptions: {
babelOptions: {
presets: [require.resolve("next/babel")],
},
project: path.join(__dirname, "/tsconfig.json"),
project: join(__dirname, "/tsconfig.json"),
},
plugins: ["@typescript-eslint", "unused-imports", "simple-import-sort"],
rules: {
"testing-library/prefer-screen-queries": "off",
"@next/next/no-html-link-for-pages": "off",
"unused-imports/no-unused-imports": "error",
"@typescript-eslint/no-unused-vars": [
"warn",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
},
],
"tailwindcss/classnames-order": "off",
"max-params": ["error", 4],
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"tailwindcss/no-custom-classname": "off",
},
overrides: [
{
files: ["**/*.js", "**/*.ts", "**/*.tsx"],
rules: {
"simple-import-sort/imports": [
"error",
{
groups: [
// `react` first, `next` second, then packages starting with a character
["^react$", "^next", "^[a-z]"],
// Packages starting with `@`
["^@"],
// Packages starting with `~`
["^~"],
// Imports starting with `../`
["^\\.\\.(?!/?$)", "^\\.\\./?$"],
// Imports starting with `./`
["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
// Style imports
["^.+\\.s?css$"],
// Side effect imports
["^\\u0000"],
],
},
],
},
},
],
extends: ["custom/next"],
}
18 changes: 7 additions & 11 deletions apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"deploy-db:prod": "prisma migrate deploy && npm run seed",
"lint": "next lint && eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "next lint --fix && eslint . --ext .js,.jsx,.ts,.tsx --fix",
"prettier": "prettier --check \"**/*.{js,jsx,ts,tsx}\"",
"prettier:fix": "prettier --write \"**/*.{js,jsx,ts,tsx}\"",
"test": "cross-env FORCE_COLOR=1 jest --passWithNoTests",
"postinstall": "patch-package && prisma generate",
"seed": "cross-env NODE_ENV=development tsx prisma/seed.ts",
Expand Down Expand Up @@ -36,8 +38,6 @@
"@types/react-dom": "^18.2.7",
"@types/request-ip": "^0.0.41",
"@types/ua-parser-js": "^0.7.39",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"autoprefixer": "^10.4.16",
"base32-encode": "^2.0.0",
"bcryptjs": "^2.4.3",
Expand All @@ -49,16 +49,9 @@
"cross-env": "^7.0.3",
"crypto-js": "^4.2.0",
"dotenv": "^16.3.1",
"eslint": "^8.55.0",
"eslint-config-next": "^14.0.3",
"eslint-config-prettier": "^9.1.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-simple-import-sort": "^12.0.0",
"eslint-plugin-tailwindcss": "^3.13.0",
"eslint-plugin-unused-imports": "^3.0.0",
"framer-motion": "^11.0.0",
"ioredis": "^5.3.2",
"lucide-react": "^0.353.0",
"lucide-react": "^0.354.0",
"negotiator": "^0.6.3",
"next": "^14.0.0",
"next-auth": "^4.24.5",
Expand All @@ -79,7 +72,10 @@
"tailwind-merge": "^2.0.0",
"tsx": "^4.7.0",
"ua-parser-js": "^1.0.35",
"zod": "^3.21.4"
"zod": "^3.21.4",
"eslint-config-custom": "*",
"tsconfig": "*",
"custom-prettier-config": "*"
},
"devDependencies": {
"@babel/core": "^7.22.17",
Expand Down
1 change: 1 addition & 0 deletions apps/app/prettier.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("custom-prettier-config/next")
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default async function Profile({
</CardHeader>
<CardBody>
<p className="text-muted-foreground">{dictionary.profilePage.serverSideData}</p>
<pre className="bg-muted mt-2 w-[40rem] max-w-full overflow-auto rounded p-2">
<pre className="mt-2 w-[40rem] max-w-full overflow-auto rounded bg-muted p-2">
{JSON.stringify(session, null, 2)}
</pre>
<div className="mt-4 flex flex-col items-center space-y-2 md:mr-0 md:w-full md:flex-row md:justify-end md:space-x-2 md:space-y-0">
Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/app/[lang]/(sys-auth)/forgot-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export default async function ForgotPassword({
<main className="container m-auto flex min-h-screen flex-1 flex-col items-center justify-center space-y-2">
<NavSettings lang={lang} />
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.forgotPasswordTitle}</h1>
<p className="text-muted-foreground text-sm">{dictionary.forgotPasswordDescription}</p>
<p className="text-sm text-muted-foreground">{dictionary.forgotPasswordDescription}</p>
<ForgotPasswordForm />
<Link href={authRoutes.signIn[0]} className="text-muted-foreground hover:text-primary text-sm">
<Link href={authRoutes.signIn[0]} className="text-sm text-muted-foreground hover:text-primary">
{dictionary.goToSignInPage}
</Link>
</main>
Expand Down
6 changes: 3 additions & 3 deletions apps/app/src/app/[lang]/(sys-auth)/privacy-acceptance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { Link } from "@nextui-org/react"

export default function PrivacyAcceptance({ dictionary }: { dictionary: TDictionary }) {
return (
<p className="text-muted-foreground px-8 text-center text-sm">
<p className="px-8 text-center text-sm text-muted-foreground">
{dictionary.auth.clickingAggreement}{" "}
<Link href="/terms" className="hover:text-primary inline text-sm underline underline-offset-4">
<Link href="/terms" className="inline text-sm underline underline-offset-4 hover:text-primary">
{dictionary.auth.termsOfService}
</Link>{" "}
{dictionary.and}{" "}
<Link href="/privacy" className="hover:text-primary inline text-sm underline underline-offset-4">
<Link href="/privacy" className="inline text-sm underline underline-offset-4 hover:text-primary">
{dictionary.auth.privacyPolicy}
</Link>
.
Expand Down
4 changes: 3 additions & 1 deletion apps/app/src/app/[lang]/(sys-auth)/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function Providers({
redirect(callbackUrl)
}

async function handleSignIn({ providerId }: { providerId: string }) {
async function handleSignIn({ providerId }: { providerId: string }): Promise<boolean> {
try {
const res = await signIn(providerId, {
callbackUrl: `${window.location.origin}${authRoutes.redirectAfterSignIn}`,
Expand All @@ -41,6 +41,7 @@ export default function Providers({
}
}
}
return true
//? Do not setIsLoading(false) here because the user will be redirected to profile
} catch (error) {
logger.error(error)
Expand All @@ -49,6 +50,7 @@ export default function Providers({
} else {
toast(dictionary.errors.unknownError)
}
return false
}
}

Expand Down
4 changes: 2 additions & 2 deletions apps/app/src/app/[lang]/(sys-auth)/recover-2fa/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default function Recover2FAForm({ email }: { email?: string }) {
placeholder={dictionary.email}
autoComplete="email"
/>
<p className="text-muted-foreground mt-6 text-sm">{dictionary.recover2FADescription}</p>
<p className="mt-6 text-sm text-muted-foreground">{dictionary.recover2FADescription}</p>
<div className="flex flex-col">
<div className="grid grid-cols-3 gap-x-6 gap-y-2" ref={divRef}>
{mnemonic.map((data, index) => {
Expand All @@ -112,7 +112,7 @@ export default function Recover2FAForm({ email }: { email?: string }) {
>
<input
className={cn(
"bg-muted rounded-medium hover:bg-primary-200/70 focus:bg-primary-200/70 group relative h-[34px] w-full min-w-[70px] p-1.5 text-sm transition-all",
"group relative h-[34px] w-full min-w-[70px] rounded-medium bg-muted p-1.5 text-sm transition-all hover:bg-primary-200/70 focus:bg-primary-200/70",
{
"bg-danger-50 hover:bg-danger-100": mnemonicError,
}
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/app/[lang]/(sys-auth)/recover-2fa/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default async function Recover2FA({
<NavSettings lang={lang} />
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.recover2FA}</h1>
<Recover2FAForm email={email} />
<Link href={authRoutes.signIn[0]} className="text-muted-foreground hover:text-primary text-sm">
<Link href={authRoutes.signIn[0]} className="text-sm text-muted-foreground hover:text-primary">
{dictionary.goToSignInPage}
</Link>
</main>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export default async function ForgotPassword({
<main className="container m-auto flex min-h-screen flex-1 flex-col items-center justify-center space-y-2">
<NavSettings lang={lang} />
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.resetPasswordTitle}</h1>
<p className="text-muted-foreground text-sm">{dictionary.resetPasswordDescription}</p>
<p className="text-sm text-muted-foreground">{dictionary.resetPasswordDescription}</p>
<ResetPasswordForm token={token} />
<Link href={authRoutes.signIn[0]} className="text-muted-foreground hover:text-primary text-sm">
<Link href={authRoutes.signIn[0]} className="text-sm text-muted-foreground hover:text-primary">
{dictionary.goToSignInPage}
</Link>
</main>
Expand Down
6 changes: 3 additions & 3 deletions apps/app/src/app/[lang]/(sys-auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ export default async function SignInPage({
{dictionary.toSignUp}
</Button>
)}
<div className="bg-muted hidden h-full lg:block"></div>
<div className="hidden h-full bg-muted lg:block"></div>
<div className="lg:p-8">
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
<div className="flex flex-col space-y-2 text-center">
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.signInPage.loginToYourAccount}</h1>
<p className="text-muted-foreground text-sm">{dictionary.signInPage.enterDetails}</p>
<p className="text-sm text-muted-foreground">{dictionary.signInPage.enterDetails}</p>
</div>
<div className="grid gap-6">
<LoginUserAuthForm searchParams={searchParams} />
Expand All @@ -53,7 +53,7 @@ export default async function SignInPage({
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background text-muted-foreground px-2">{dictionary.auth.orContinueWith}</span>
<span className="bg-background px-2 text-muted-foreground">{dictionary.auth.orContinueWith}</span>
</div>
</div>
<Providers searchParams={searchParams} session={session} />
Expand Down
6 changes: 3 additions & 3 deletions apps/app/src/app/[lang]/(sys-auth)/sign-up/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ export default async function SignUpPage({
>
{dictionary.login}
</Button>
<div className="bg-muted hidden h-full lg:block"></div>
<div className="hidden h-full bg-muted lg:block"></div>
<div className="lg:p-8">
<div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
<div className="flex flex-col space-y-2 text-center">
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.signUpPage.createAnAccount}</h1>
<p className="text-muted-foreground text-sm">{dictionary.signUpPage.enterEmail}</p>
<p className="text-sm text-muted-foreground">{dictionary.signUpPage.enterEmail}</p>
</div>
<div className="grid gap-6">
<RegisterUserAuthForm isMinimized searchParams={searchParams} locale={lang} />
Expand All @@ -48,7 +48,7 @@ export default async function SignUpPage({
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-background text-muted-foreground px-2">{dictionary.auth.orContinueWith}</span>
<span className="bg-background px-2 text-muted-foreground">{dictionary.auth.orContinueWith}</span>
</div>
</div>
<Providers searchParams={searchParams} session={session} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export default async function VerifyEmail({
<main className="container m-auto flex min-h-screen flex-1 flex-col items-center justify-center space-y-2">
<NavSettings lang={lang} />
<h1 className="text-2xl font-semibold tracking-tight">{dictionary.emailVerificationTitle}</h1>
<p className="text-muted-foreground text-sm">{dictionary.emailVerificationDescription}</p>
<p className="text-sm text-muted-foreground">{dictionary.emailVerificationDescription}</p>
<VerifyEmailButton token={token} />
<Link href={authRoutes.signIn[0]} className="text-muted-foreground hover:text-primary text-sm">
<Link href={authRoutes.signIn[0]} className="text-sm text-muted-foreground hover:text-primary">
{dictionary.goToSignInPage}
</Link>
</main>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default async function RootLayout({

return (
<html lang={params.lang}>
<body className={cn("antialiaseds bg-background min-h-screen font-sans", fontSans.variable)}>
<body className={cn("antialiaseds min-h-screen bg-background font-sans", fontSans.variable)}>
<RootProviders
dictionary={hasDictLoaded ? undefined : dictionary}
lang={params.lang as Locale}
Expand Down
8 changes: 5 additions & 3 deletions apps/app/src/components/auth/github-sign-in.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function GithubSignIn({
handleSignIn,
}: {
providerId: string
handleSignIn: ({ depth, otp, providerId }: { depth?: number; otp?: string; providerId: string }) => Promise<void>
handleSignIn: ({ depth, otp, providerId }: { depth?: number; otp?: string; providerId: string }) => Promise<boolean>
}) {
const [isLoading, setIsLoading] = useState(false)

Expand All @@ -21,9 +21,11 @@ export default function GithubSignIn({
variant="ghost"
color="primary"
type="button"
onClick={() => {
onPress={async () => {
setIsLoading(true)
handleSignIn({ providerId }).finally(() => setIsLoading(false))
const res = await handleSignIn({ providerId })
// If not a success
if (!res) setIsLoading(false)
}}
isDisabled={isLoading}
>
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/components/auth/login-user-auth-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export function LoginUserAuthForm({ searchParams, ...props }: UserAuthFormProps)
autoCorrect="off"
isDisabled={isLoading}
/>
<Link className="text-muted-foreground hover:text-primary ml-auto text-sm" href={"/forgot-password"}>
<Link className="ml-auto text-sm text-muted-foreground hover:text-primary" href={"/forgot-password"}>
{dictionary.forgotPassword}
</Link>
<Button type="submit" isLoading={isLoading} color="primary">
Expand Down
3 changes: 2 additions & 1 deletion apps/app/src/components/auth/sign-out-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default function SignoutButton({ children }: { children: React.ReactNode
logger.error(e)
}
await signOut({ callbackUrl: authRoutes.signIn[0] })
setSignOutLoading(false)
// Do not set signOutLoading to false, as the user will be redirected
// setSignOutLoading(false)
}

return (
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/components/auth/verify-email-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function VerifyEmailButton({ session }: { session: Session }) {

if (hasVerifiedEmail) {
return (
<p className="text-primary flex w-max flex-1 items-center space-x-2 font-medium">
<p className="flex w-max flex-1 items-center space-x-2 font-medium text-primary">
<BadgeCheck className="inline-block size-5" />
<span>{dictionary.emailAlreadyVerified}</span>
</p>
Expand Down
Loading
Loading