Skip to content

Commit 6a8d8fc

Browse files
revise auth
1 parent 6a9d762 commit 6a8d8fc

File tree

25 files changed

+182
-214
lines changed

25 files changed

+182
-214
lines changed

packages/devextreme-cli/src/applications/application.nextjs.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const isTsApp = () => {
3636
};
3737

3838
const getExtension = (appPath) => {
39-
return fs.existsSync(path.join(appPath, 'src/app', 'page.tsx')) ? '.tsx' : '.jsx';
39+
return fs.existsSync(path.join(appPath, 'src/app', 'layout.tsx')) ? '.tsx' : '.jsx';
4040
};
4141

4242
const pathToPagesIndex = () => {
@@ -47,6 +47,7 @@ const pathToPagesIndex = () => {
4747
const preparePackageJsonForTemplate = (appPath, appName) => {
4848
const dependencies = [
4949
{ name: 'devextreme-cli', version: latestVersions['devextreme-cli'], dev: true },
50+
{ name: 'jose', version: latestVersions['jose'] },
5051
];
5152
const scripts = [
5253
{ name: 'build-themes', value: 'devextreme build' },
@@ -74,20 +75,15 @@ const create = async(appName, options) => {
7475
commandArguments = [
7576
...commandArguments,
7677
`${templateOptions.isTypeScript ? '--typescript' : '--javascript'}`,
77-
'--eslint',
78-
'--no-tailwind',
79-
'--src-dir',
80-
'--app',
81-
'--no-turbopack',
82-
'--import-alias "@/*"'
78+
'--yes',
8379
];
8480

8581
await runCommand('npx', commandArguments);
8682

8783
const appPath = path.join(process.cwd(), appName);
8884

8985
if(depsVersionTag) {
90-
bumpReact(appPath, depsVersionTag);
86+
bumpReact(appPath, depsVersionTag, templateOptions.isTypeScript);
9187
}
9288

9389
addTemplate(appPath, appName, templateOptions);

packages/devextreme-cli/src/applications/application.react.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,19 @@ const updateJsonPropName = (path, name) => {
5252
});
5353
};
5454

55-
const bumpReact = (appPath, versionTag) => {
55+
const bumpReact = (appPath, versionTag, isTypeScript) => {
5656
const dependencies = [
5757
{ name: 'react', version: versionTag },
5858
{ name: 'react-dom', version: versionTag },
59-
{ name: '@types/react', version: versionTag, dev: true },
60-
{ name: '@types/react-dom', version: versionTag, dev: true },
6159
];
6260

61+
if(isTypeScript) {
62+
dependencies.push(
63+
{ name: '@types/react', version: versionTag, dev: true },
64+
{ name: '@types/react-dom', version: versionTag, dev: true },
65+
);
66+
}
67+
6368
packageJsonUtils.addDependencies(appPath, dependencies);
6469
};
6570

@@ -86,7 +91,7 @@ const create = async(appName, options) => {
8691
modifyIndexHtml(appPath, templateOptions.project);
8792

8893
if(depsVersionTag) {
89-
bumpReact(appPath, depsVersionTag);
94+
bumpReact(appPath, depsVersionTag, templateOptions.isTypeScript);
9095
}
9196

9297
addTemplate(appPath, appName, templateOptions);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SESSION_SECRET=<your_secret_key_goes_here>

packages/devextreme-cli/src/templates/nextjs/application/src/api/auth.tsx

Lines changed: 0 additions & 86 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use server'
2+
import { redirect } from 'next/navigation'
3+
import defaultUser from '@/utils/default-user';
4+
import { createSession, deleteSession } from '@/app/lib/session'
5+
6+
export async function signUp(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
7+
// Create a user in the database
8+
console.log(email, password);
9+
10+
await signIn(email, password);
11+
}
12+
13+
export async function signIn(email<%=#isTypeScript%>: string<%=/isTypeScript%>, password<%=#isTypeScript%>: string<%=/isTypeScript%>) {
14+
// Verify that a user exists
15+
console.log(email, password);
16+
17+
await createSession(defaultUser.id);
18+
}
19+
20+
export async function signOut() {
21+
await deleteSession();
22+
redirect('/login');
23+
}
24+
25+
export async function changePassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>, recoveryCode?<%=#isTypeScript%>: string<%=/isTypeScript%>) {
26+
// Verify the recovery code
27+
console.log(email, recoveryCode);
28+
}
29+
30+
export async function resetPassword(email<%=#isTypeScript%>: string<%=/isTypeScript%>) {
31+
// Reset password
32+
console.log(email);
33+
}

packages/devextreme-cli/src/templates/nextjs/application/src/app/layout.tsx

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
1-
'use client'
2-
<%=#isTypeScript%>import { PropsWithChildren } from 'react';<%=/isTypeScript%>
3-
import LoadPanel from 'devextreme-react/load-panel';
4-
import { AuthProvider, useAuth } from '@/contexts/auth';
5-
import { ThemeProvider } from "@/theme";
6-
7-
function Page({ children }<%=#isTypeScript%>: PropsWithChildren<object><%=/isTypeScript%>) {
8-
const { loading } = useAuth();
9-
10-
if (loading) {
11-
return <LoadPanel visible={true} />;
12-
}
13-
14-
return children;
15-
}
1+
<%=#isTypeScript%>import type { PropsWithChildren } from 'react';
2+
<%=/isTypeScript%>import { ThemeProvider } from "@/theme";
163

174
export default function RootLayout({ children }<%=#isTypeScript%>: PropsWithChildren<object><%=/isTypeScript%>) {
185
return (
196
<html lang="en">
207
<title>NextJs Dx App</title>
218
<body className="dx-viewport">
229
<ThemeProvider>
23-
<AuthProvider>
24-
<div className='app'>
25-
<Page>{children}</Page>
26-
</div>
27-
</AuthProvider>
10+
<div className='app'>
11+
{children}
12+
</div>
2813
</ThemeProvider>
2914
</body>
3015
</html>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import 'server-only';
2+
import { SignJWT, jwtVerify } from 'jose';
3+
import { cookies } from 'next/headers';
4+
<%=#isTypeScript%>import type { SessionPayload } from '@/types';
5+
<%=/isTypeScript%>
6+
const secretKey = process.env.SESSION_SECRET;
7+
const encoder = new TextEncoder();
8+
const encodedKey = encoder.encode(secretKey);
9+
10+
export async function encrypt(payload<%=#isTypeScript%>: SessionPayload<%=/isTypeScript%>) {
11+
return new SignJWT(payload)
12+
.setProtectedHeader({ alg: 'HS256' })
13+
.setIssuedAt()
14+
.setExpirationTime('7d')
15+
.sign(encodedKey);
16+
}
17+
18+
export async function decrypt(session<%=#isTypeScript%>: string | undefined = ''<%=/isTypeScript%>) {
19+
try {
20+
const { payload } = await jwtVerify(session, encodedKey, {
21+
algorithms: ['HS256'],
22+
});
23+
24+
return payload;
25+
} catch (error) {
26+
console.log('Failed to verify session');
27+
}
28+
}
29+
30+
export async function createSession(userId<%=#isTypeScript%>: string<%=/isTypeScript%>) {
31+
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
32+
const session = await encrypt({ userId, expiresAt });
33+
const cookieStore = await cookies();
34+
35+
cookieStore.set('session', session, {
36+
httpOnly: true,
37+
secure: true,
38+
expires: expiresAt,
39+
sameSite: 'lax',
40+
path: '/',
41+
});
42+
}
43+
44+
export async function deleteSession() {
45+
const cookieStore = await cookies();
46+
cookieStore.delete('session');
47+
}

packages/devextreme-cli/src/templates/nextjs/application/src/app/pages/layout.tsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
1-
'use client'
2-
import {<%=#isTypeScript%> PropsWithChildren,<%=/isTypeScript%> useEffect } from 'react';
3-
import { useRouter } from 'next/navigation';
4-
import { useAuth } from '@/contexts/auth';
5-
import appInfo from '@/app-info';
1+
<%=#isTypeScript%>import type { PropsWithChildren } from 'react';
2+
<%=/isTypeScript%>import appInfo from '@/app-info';
63
import { Footer } from '@/components';
74
import { <%=layout%> as SideNavBarLayout } from '@/layouts';
85

96
export default function Content({children}<%=#isTypeScript%>: PropsWithChildren<object><%=/isTypeScript%>) {
10-
const { user, loading } = useAuth();
11-
const router = useRouter();
12-
13-
useEffect(() => {
14-
if (!loading && !user) {
15-
router.push('/login');
16-
}
17-
}, [user, loading, router]);
18-
197
return (
208
<SideNavBarLayout title={appInfo.title}>
219
{children}

packages/devextreme-cli/src/templates/nextjs/application/src/components/create-account-form/CreateAccountForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Form, {
1313
} from 'devextreme-react/form';
1414
import notify from 'devextreme/ui/notify';
1515
import LoadIndicator from 'devextreme-react/load-indicator';
16-
import { createAccount } from '../../api/auth';
16+
import { signUp } from '@/app/actions/auth';
1717
<%=#isTypeScript%>import { ValidationCallbackData } from 'devextreme-react/common';<%=/isTypeScript%>
1818
import './CreateAccountForm.scss';
1919

@@ -27,7 +27,7 @@ export default function CreateAccountForm() {
2727
const { email, password } = formData.current;
2828
setLoading(true);
2929

30-
const result = await createAccount(email, password);
30+
const result = await signUp(email, password);
3131
setLoading(false);
3232

3333
if (result.isOk) {

packages/devextreme-cli/src/templates/nextjs/application/src/components/header/Header.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import Toolbar, { Item } from 'devextreme-react/toolbar';
22
import Button from 'devextreme-react/button';
3-
import UserPanel from '../user-panel/UserPanel';
3+
import UserPanel from '@/components/user-panel/UserPanel';
44
import './Header.scss';
55
import { Template } from 'devextreme-react/core/template';
6-
import { ThemeSwitcher } from '../theme-switcher/ThemeSwitcher';
7-
<%=#isTypeScript%>import type { HeaderProps } from '../../types';<%=/isTypeScript%>
6+
import { ThemeSwitcher } from '@/components/theme-switcher/ThemeSwitcher';
7+
<%=#isTypeScript%>import type { HeaderProps } from '@/types';<%=/isTypeScript%>
88

99
export default function Header({ menuToggleEnabled, title, toggleMenu }<%=#isTypeScript%>: HeaderProps<%=/isTypeScript%>) {
1010
return (

0 commit comments

Comments
 (0)