@idevconn/create-icore 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +36 -27
- package/dist/index.cjs +36 -27
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +36 -27
- package/package.json +3 -1
- package/templates/apps/api/.env.example +20 -0
- package/templates/apps/api/tsconfig.json +6 -1
- package/templates/apps/microservices/auth/.env.example +5 -0
- package/templates/apps/microservices/auth/tsconfig.json +6 -1
- package/templates/apps/microservices/jobs/tsconfig.json +6 -1
- package/templates/apps/microservices/notes/.env.example +5 -0
- package/templates/apps/microservices/notes/tsconfig.json +6 -1
- package/templates/apps/microservices/notes-e2e/src/support/global.d.ts +6 -0
- package/templates/apps/microservices/payment/.env.example +5 -0
- package/templates/apps/microservices/payment/tsconfig.json +6 -1
- package/templates/apps/microservices/upload/.env.example +5 -0
- package/templates/apps/microservices/upload/tsconfig.json +6 -1
- package/templates/apps/templates/client-antd/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-antd/src/components/layout/LayoutHeader.tsx +1 -1
- package/templates/apps/templates/client-antd/src/components/layout/LayoutSider.tsx +3 -3
- package/templates/apps/templates/client-antd/src/routes/_dashboard/dashboard.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/_dashboard/notes.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/_dashboard/profile.tsx +2 -2
- package/templates/apps/templates/client-antd/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-antd/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-antd/src/routes/login.tsx +1 -1
- package/templates/apps/templates/client-antd/tsconfig.json +6 -1
- package/templates/apps/templates/client-antd-e2e/src/icore.spec.ts +2 -2
- package/templates/apps/templates/client-mui/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-mui/src/components/layout/LayoutHeader.tsx +1 -1
- package/templates/apps/templates/client-mui/src/components/layout/LayoutSider.tsx +3 -15
- package/templates/apps/templates/client-mui/src/routes/_dashboard/dashboard.tsx +2 -6
- package/templates/apps/templates/client-mui/src/routes/_dashboard/notes.tsx +2 -2
- package/templates/apps/templates/client-mui/src/routes/_dashboard/profile.tsx +3 -3
- package/templates/apps/templates/client-mui/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-mui/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-mui/src/routes/login.tsx +3 -3
- package/templates/apps/templates/client-mui/tsconfig.json +6 -1
- package/templates/apps/templates/client-mui-e2e/src/icore.spec.ts +2 -2
- package/templates/apps/templates/client-shadcn/src/components/AccessDeniedPage.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/layout/LayoutSider.tsx +3 -3
- package/templates/apps/templates/client-shadcn/src/components/notes/DeleteNoteConfirm.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/notes/NoteDialog.tsx +3 -3
- package/templates/apps/templates/client-shadcn/src/components/notes/NotesTable.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/button.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/card.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/input.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/components/ui/label.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/dashboard.tsx +3 -9
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/notes.tsx +6 -6
- package/templates/apps/templates/client-shadcn/src/routes/_dashboard/profile.tsx +7 -7
- package/templates/apps/templates/client-shadcn/src/routes/auth.callback.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/auth.oauth.callback.tsx +1 -1
- package/templates/apps/templates/client-shadcn/src/routes/login.tsx +19 -12
- package/templates/apps/templates/client-shadcn/tsconfig.json +6 -1
- package/templates/libs/auth-strategies/firebase/src/lib/__tests__/firebase-auth.contract.unit.test.ts +7 -4
- package/templates/libs/auth-strategies/supabase/src/lib/__tests__/supabase-auth.contract.unit.test.ts +6 -3
- package/templates/libs/db-strategies/firestore/src/lib/__tests__/firestore-db.contract.unit.test.ts +2 -3
- package/templates/libs/db-strategies/supabase/src/lib/__tests__/supabase-db.contract.unit.test.ts +2 -3
- package/templates/libs/firebase-admin/tsconfig.json +2 -1
- package/templates/libs/jobs-client/tsconfig.json +2 -1
- package/templates/libs/notes-client/tsconfig.json +2 -1
- package/templates/libs/payment-client/tsconfig.json +2 -1
- package/templates/libs/shared/src/__tests__/cross-boundary.unit.test.ts +2 -1
- package/templates/libs/shared/src/__tests__/transport.unit.test.ts +47 -8
- package/templates/libs/shared/src/abilities/subjects.ts +12 -1
- package/templates/libs/shared/src/strategies/__tests__/fake-auth.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/strategies/__tests__/fake-db.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/strategies/__tests__/fake-storage.contract.unit.test.ts +2 -2
- package/templates/libs/shared/src/strategies/index.ts +3 -3
- package/templates/libs/shared/src/testing.ts +14 -0
- package/templates/libs/shared/src/transport.ts +41 -0
- package/templates/libs/shared/tsconfig.lib.json +3 -1
- package/templates/libs/shared/vitest.config.mts +11 -1
- package/templates/libs/storage-strategies/cloudinary/src/lib/__tests__/cloudinary-storage.contract.unit.test.ts +2 -3
- package/templates/libs/storage-strategies/firebase/src/lib/__tests__/firebase-storage.contract.unit.test.ts +2 -3
- package/templates/libs/storage-strategies/supabase/src/lib/__tests__/supabase-storage.contract.unit.test.ts +2 -3
- package/templates/libs/vite-plugins/src/index.d.mts +5 -7
- package/templates/libs/vite-plugins/src/index.mjs +1 -1
- package/templates/libs/vite-plugins/tsconfig.json +2 -1
- package/templates/tsconfig.base.json +1 -0
- /package/templates/libs/shared/src/strategies/{contract/auth-contract.ts → __tests__/auth.contract.unit.test.ts} +0 -0
- /package/templates/libs/shared/src/strategies/{contract/db-contract.ts → __tests__/db.contract.unit.test.ts} +0 -0
- /package/templates/libs/shared/src/strategies/{contract/storage-contract.ts → __tests__/storage.contract.unit.test.ts} +0 -0
|
@@ -19,17 +19,17 @@ export function LayoutSider() {
|
|
|
19
19
|
{
|
|
20
20
|
key: 'dashboard',
|
|
21
21
|
icon: <DashboardOutlined />,
|
|
22
|
-
label: <Link to="/
|
|
22
|
+
label: <Link to="/dashboard">{t('nav.dashboard')}</Link>,
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
key: 'notes',
|
|
26
26
|
icon: <FileTextOutlined />,
|
|
27
|
-
label: <Link to="/
|
|
27
|
+
label: <Link to="/notes">{t('notes.title')}</Link>,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
key: 'profile',
|
|
31
31
|
icon: <UserOutlined />,
|
|
32
|
-
label: <Link to="/
|
|
32
|
+
label: <Link to="/profile">{t('nav.profile')}</Link>,
|
|
33
33
|
},
|
|
34
34
|
];
|
|
35
35
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
2
2
|
import { Button, Card } from 'antd';
|
|
3
3
|
import { useAuthStore } from '@icore/template-shared';
|
|
4
|
-
import { PageLayout } from '
|
|
4
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
5
5
|
|
|
6
6
|
function DashboardHome() {
|
|
7
7
|
const user = useAuthStore((s) => s.user);
|
|
@@ -11,7 +11,7 @@ function DashboardHome() {
|
|
|
11
11
|
title="Hello, world"
|
|
12
12
|
style={{ maxWidth: 600 }}
|
|
13
13
|
extra={
|
|
14
|
-
<Link to="/
|
|
14
|
+
<Link to="/profile">
|
|
15
15
|
<Button type="link">Go to profile →</Button>
|
|
16
16
|
</Link>
|
|
17
17
|
}
|
|
@@ -3,14 +3,14 @@ import { useState } from 'react';
|
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { Button, Form, Input, Modal, Popconfirm, Space, Table, Typography } from 'antd';
|
|
5
5
|
import type { ColumnsType } from 'antd/es/table';
|
|
6
|
-
import { PageLayout } from '
|
|
6
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
7
7
|
import {
|
|
8
8
|
useCreateNote,
|
|
9
9
|
useDeleteNote,
|
|
10
10
|
useNotesList,
|
|
11
11
|
useUpdateNote,
|
|
12
12
|
type Note,
|
|
13
|
-
} from '
|
|
13
|
+
} from '@/queries/notes';
|
|
14
14
|
|
|
15
15
|
const PAGE_SIZE = 20;
|
|
16
16
|
|
|
@@ -3,8 +3,8 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import { Button, Form, Input } from 'antd';
|
|
5
5
|
import { useDraft, useNotify, useAuthStore } from '@icore/template-shared';
|
|
6
|
-
import { PageLayout } from '
|
|
7
|
-
import { api } from '
|
|
6
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
7
|
+
import { api } from '@/main';
|
|
8
8
|
|
|
9
9
|
interface ProfilePayload {
|
|
10
10
|
uid: string;
|
|
@@ -41,7 +41,7 @@ function LoginPage() {
|
|
|
41
41
|
});
|
|
42
42
|
setAuth(session);
|
|
43
43
|
notify.success(t('auth.login'));
|
|
44
|
-
await navigate({ to: '/
|
|
44
|
+
await navigate({ to: '/dashboard' });
|
|
45
45
|
} catch (err) {
|
|
46
46
|
notify.error(err instanceof Error ? err.message : t('error.unknown'));
|
|
47
47
|
}
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
"esModuleInterop": false,
|
|
9
9
|
"allowSyntheticDefaultImports": true,
|
|
10
10
|
"strict": true,
|
|
11
|
-
"types": ["vite/client", "vitest"]
|
|
11
|
+
"types": ["vite/client", "vitest"],
|
|
12
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": ["./src/*"]
|
|
15
|
+
},
|
|
16
|
+
"baseUrl": "."
|
|
12
17
|
},
|
|
13
18
|
"files": [],
|
|
14
19
|
"include": [],
|
|
@@ -14,12 +14,12 @@ test.describe('icore client-antd smoke', () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
test('protected route redirects to login when unauthenticated', async ({ page }) => {
|
|
17
|
-
await page.goto('/
|
|
17
|
+
await page.goto('/dashboard');
|
|
18
18
|
await expect(page).toHaveURL(/\/login$/);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('profile route redirects to login when unauthenticated', async ({ page }) => {
|
|
22
|
-
await page.goto('/
|
|
22
|
+
await page.goto('/profile');
|
|
23
23
|
await expect(page).toHaveURL(/\/login$/);
|
|
24
24
|
});
|
|
25
25
|
});
|
|
@@ -16,7 +16,7 @@ export function AccessDeniedPage() {
|
|
|
16
16
|
{t('error.unknown')}
|
|
17
17
|
</Typography>
|
|
18
18
|
<Box>
|
|
19
|
-
<Button component={Link} to="/
|
|
19
|
+
<Button component={Link} to="/dashboard" variant="contained">
|
|
20
20
|
Dashboard
|
|
21
21
|
</Button>
|
|
22
22
|
</Box>
|
|
@@ -91,7 +91,7 @@ export function LayoutHeader() {
|
|
|
91
91
|
{user?.email ?? ''}
|
|
92
92
|
</Typography>
|
|
93
93
|
</MenuItem>
|
|
94
|
-
<MenuItem component={Link} to="/
|
|
94
|
+
<MenuItem component={Link} to="/profile" onClick={handleMenuClose}>
|
|
95
95
|
{t('nav.profile')}
|
|
96
96
|
</MenuItem>
|
|
97
97
|
<MenuItem onClick={handleLogout} sx={{ color: 'error.main' }}>
|
|
@@ -25,33 +25,21 @@ export function LayoutSider() {
|
|
|
25
25
|
}}
|
|
26
26
|
>
|
|
27
27
|
<List>
|
|
28
|
-
<ListItemButton
|
|
29
|
-
component={Link}
|
|
30
|
-
to="/_dashboard/dashboard"
|
|
31
|
-
selected={pathname === '/dashboard'}
|
|
32
|
-
>
|
|
28
|
+
<ListItemButton component={Link} to="/dashboard" selected={pathname === '/dashboard'}>
|
|
33
29
|
<ListItemIcon>
|
|
34
30
|
<DashboardOutlinedIcon />
|
|
35
31
|
</ListItemIcon>
|
|
36
32
|
<ListItemText primary={t('nav.dashboard')} />
|
|
37
33
|
</ListItemButton>
|
|
38
34
|
|
|
39
|
-
<ListItemButton
|
|
40
|
-
component={Link}
|
|
41
|
-
to="/_dashboard/notes"
|
|
42
|
-
selected={pathname.includes('/notes')}
|
|
43
|
-
>
|
|
35
|
+
<ListItemButton component={Link} to="/notes" selected={pathname.includes('/notes')}>
|
|
44
36
|
<ListItemIcon>
|
|
45
37
|
<NoteOutlinedIcon />
|
|
46
38
|
</ListItemIcon>
|
|
47
39
|
<ListItemText primary={t('notes.title')} />
|
|
48
40
|
</ListItemButton>
|
|
49
41
|
|
|
50
|
-
<ListItemButton
|
|
51
|
-
component={Link}
|
|
52
|
-
to="/_dashboard/profile"
|
|
53
|
-
selected={pathname === '/profile'}
|
|
54
|
-
>
|
|
42
|
+
<ListItemButton component={Link} to="/profile" selected={pathname === '/profile'}>
|
|
55
43
|
<ListItemIcon>
|
|
56
44
|
<PersonOutlineIcon />
|
|
57
45
|
</ListItemIcon>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
2
2
|
import { Card, CardContent, CardHeader, Typography } from '@mui/material';
|
|
3
3
|
import { useAuthStore } from '@icore/template-shared';
|
|
4
|
-
import { PageLayout } from '
|
|
4
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
5
5
|
|
|
6
6
|
function DashboardHome() {
|
|
7
7
|
const user = useAuthStore((s) => s.user);
|
|
@@ -13,11 +13,7 @@ function DashboardHome() {
|
|
|
13
13
|
subheader="Edit this page in src/routes/_dashboard/dashboard.tsx"
|
|
14
14
|
/>
|
|
15
15
|
<CardContent>
|
|
16
|
-
<Typography
|
|
17
|
-
component={Link}
|
|
18
|
-
to="/_dashboard/profile"
|
|
19
|
-
sx={{ textDecoration: 'underline' }}
|
|
20
|
-
>
|
|
16
|
+
<Typography component={Link} to="/profile" sx={{ textDecoration: 'underline' }}>
|
|
21
17
|
Go to profile →
|
|
22
18
|
</Typography>
|
|
23
19
|
</CardContent>
|
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
} from '@mui/material';
|
|
23
23
|
import EditIcon from '@mui/icons-material/Edit';
|
|
24
24
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
25
|
-
import { PageLayout } from '
|
|
25
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
26
26
|
import {
|
|
27
27
|
useCreateNote,
|
|
28
28
|
useDeleteNote,
|
|
29
29
|
useNotesList,
|
|
30
30
|
useUpdateNote,
|
|
31
31
|
type Note,
|
|
32
|
-
} from '
|
|
32
|
+
} from '@/queries/notes';
|
|
33
33
|
|
|
34
34
|
const PAGE_SIZE = 20;
|
|
35
35
|
|
|
@@ -3,8 +3,8 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import { Box, Button, TextField } from '@mui/material';
|
|
5
5
|
import { useDraft, useNotify, useAuthStore } from '@icore/template-shared';
|
|
6
|
-
import { PageLayout } from '
|
|
7
|
-
import { api } from '
|
|
6
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
7
|
+
import { api } from '@/main';
|
|
8
8
|
|
|
9
9
|
interface ProfilePayload {
|
|
10
10
|
uid: string;
|
|
@@ -45,7 +45,7 @@ function ProfilePage() {
|
|
|
45
45
|
onError: (err) => notify.error(err instanceof Error ? err.message : 'save_failed'),
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
function handleSubmit(e: React.
|
|
48
|
+
function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
|
|
49
49
|
e.preventDefault();
|
|
50
50
|
save.mutate(name);
|
|
51
51
|
}
|
|
@@ -32,7 +32,7 @@ function LoginPage() {
|
|
|
32
32
|
const [sentEmail, setSentEmail] = useState('');
|
|
33
33
|
const [submitting, setSubmitting] = useState(false);
|
|
34
34
|
|
|
35
|
-
async function handlePasswordSubmit(e: React.
|
|
35
|
+
async function handlePasswordSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
|
|
36
36
|
e.preventDefault();
|
|
37
37
|
setSubmitting(true);
|
|
38
38
|
try {
|
|
@@ -47,7 +47,7 @@ function LoginPage() {
|
|
|
47
47
|
});
|
|
48
48
|
setAuth(session);
|
|
49
49
|
notify.success(t('auth.login'));
|
|
50
|
-
await navigate({ to: '/
|
|
50
|
+
await navigate({ to: '/dashboard' });
|
|
51
51
|
} catch (err) {
|
|
52
52
|
notify.error(err instanceof Error ? err.message : t('error.unknown'));
|
|
53
53
|
} finally {
|
|
@@ -55,7 +55,7 @@ function LoginPage() {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
async function handleMagicLinkSubmit(e: React.
|
|
58
|
+
async function handleMagicLinkSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
|
|
59
59
|
e.preventDefault();
|
|
60
60
|
setSubmitting(true);
|
|
61
61
|
try {
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
"esModuleInterop": false,
|
|
9
9
|
"allowSyntheticDefaultImports": true,
|
|
10
10
|
"strict": true,
|
|
11
|
-
"types": ["vite/client", "vitest"]
|
|
11
|
+
"types": ["vite/client", "vitest"],
|
|
12
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": ["./src/*"]
|
|
15
|
+
},
|
|
16
|
+
"baseUrl": "."
|
|
12
17
|
},
|
|
13
18
|
"files": [],
|
|
14
19
|
"include": [],
|
|
@@ -14,12 +14,12 @@ test.describe('icore client-mui smoke', () => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
test('protected route redirects to login when unauthenticated', async ({ page }) => {
|
|
17
|
-
await page.goto('/
|
|
17
|
+
await page.goto('/dashboard');
|
|
18
18
|
await expect(page).toHaveURL(/\/login$/);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('profile route redirects to login when unauthenticated', async ({ page }) => {
|
|
22
|
-
await page.goto('/
|
|
22
|
+
await page.goto('/profile');
|
|
23
23
|
await expect(page).toHaveURL(/\/login$/);
|
|
24
24
|
});
|
|
25
25
|
});
|
|
@@ -7,7 +7,7 @@ export function AccessDeniedPage() {
|
|
|
7
7
|
<div className="min-h-[60vh] flex flex-col items-center justify-center gap-2 text-center px-6">
|
|
8
8
|
<h1 className="text-2xl font-semibold">{t('error.accessDenied')}</h1>
|
|
9
9
|
<p className="text-muted-foreground">{t('error.unknown')}</p>
|
|
10
|
-
<Link to="/
|
|
10
|
+
<Link to="/dashboard" className="mt-4 underline">
|
|
11
11
|
← Dashboard
|
|
12
12
|
</Link>
|
|
13
13
|
</div>
|
|
@@ -15,7 +15,7 @@ export function LayoutSider() {
|
|
|
15
15
|
>
|
|
16
16
|
<nav className="flex flex-col gap-1 p-2 flex-1">
|
|
17
17
|
<Link
|
|
18
|
-
to="/
|
|
18
|
+
to="/dashboard"
|
|
19
19
|
activeOptions={{ exact: true }}
|
|
20
20
|
className="flex items-center gap-2 px-2 py-2 rounded hover:bg-muted text-sm text-foreground transition-colors [&.active]:bg-muted [&.active]:font-medium"
|
|
21
21
|
>
|
|
@@ -23,14 +23,14 @@ export function LayoutSider() {
|
|
|
23
23
|
{!collapsed && <span>{t('nav.dashboard')}</span>}
|
|
24
24
|
</Link>
|
|
25
25
|
<Link
|
|
26
|
-
to="/
|
|
26
|
+
to="/notes"
|
|
27
27
|
className="flex items-center gap-2 px-2 py-2 rounded hover:bg-muted text-sm text-foreground transition-colors [&.active]:bg-muted [&.active]:font-medium"
|
|
28
28
|
>
|
|
29
29
|
<StickyNote size={16} className="shrink-0" />
|
|
30
30
|
{!collapsed && <span>{t('notes.title')}</span>}
|
|
31
31
|
</Link>
|
|
32
32
|
<Link
|
|
33
|
-
to="/
|
|
33
|
+
to="/profile"
|
|
34
34
|
className="flex items-center gap-2 px-2 py-2 rounded hover:bg-muted text-sm text-foreground transition-colors [&.active]:bg-muted [&.active]:font-medium"
|
|
35
35
|
>
|
|
36
36
|
<User size={16} className="shrink-0" />
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyntheticEvent, useEffect, useState } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import { Button } from '../ui/button';
|
|
4
4
|
import { Input } from '../ui/input';
|
|
5
5
|
import { Label } from '../ui/label';
|
|
6
|
-
import type { Note } from '
|
|
6
|
+
import type { Note } from '@/queries/notes';
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
open: boolean;
|
|
@@ -27,7 +27,7 @@ export function NoteDialog({ open, initial, saving, onClose, onSubmit }: Props)
|
|
|
27
27
|
|
|
28
28
|
if (!open) return null;
|
|
29
29
|
|
|
30
|
-
function handleSubmit(e:
|
|
30
|
+
function handleSubmit(e: SyntheticEvent<HTMLFormElement>) {
|
|
31
31
|
e.preventDefault();
|
|
32
32
|
onSubmit({ title, body });
|
|
33
33
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Slot } from '@radix-ui/react-slot';
|
|
3
3
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
-
import { cn } from '
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
5
|
|
|
6
6
|
const buttonVariants = cva(
|
|
7
7
|
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// vendored design-system primitives that always travel together are kept
|
|
5
5
|
// in a single file matching the upstream shadcn source structure.
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import { cn } from '
|
|
7
|
+
import { cn } from '@/lib/utils';
|
|
8
8
|
|
|
9
9
|
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
10
10
|
({ className, ...props }, ref) => (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
3
3
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
-
import { cn } from '
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
5
|
|
|
6
6
|
const labelVariants = cva(
|
|
7
7
|
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
2
2
|
import { useAuthStore } from '@icore/template-shared';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
CardContent,
|
|
6
|
-
CardDescription,
|
|
7
|
-
CardHeader,
|
|
8
|
-
CardTitle,
|
|
9
|
-
} from '../../components/ui/card';
|
|
10
|
-
import { PageLayout } from '../../components/PageLayout';
|
|
3
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
4
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
11
5
|
|
|
12
6
|
function DashboardHome() {
|
|
13
7
|
const user = useAuthStore((s) => s.user);
|
|
@@ -19,7 +13,7 @@ function DashboardHome() {
|
|
|
19
13
|
<CardDescription>Edit this page in src/routes/_dashboard/dashboard.tsx</CardDescription>
|
|
20
14
|
</CardHeader>
|
|
21
15
|
<CardContent>
|
|
22
|
-
<Link to="/
|
|
16
|
+
<Link to="/profile" className="underline">
|
|
23
17
|
Go to profile →
|
|
24
18
|
</Link>
|
|
25
19
|
</CardContent>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router';
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { PageLayout } from '
|
|
5
|
-
import { Button } from '
|
|
6
|
-
import { NotesTable } from '
|
|
7
|
-
import { NoteDialog } from '
|
|
8
|
-
import { DeleteNoteConfirm } from '
|
|
4
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
5
|
+
import { Button } from '@/components/ui/button';
|
|
6
|
+
import { NotesTable } from '@/components/notes/NotesTable';
|
|
7
|
+
import { NoteDialog } from '@/components/notes/NoteDialog';
|
|
8
|
+
import { DeleteNoteConfirm } from '@/components/notes/DeleteNoteConfirm';
|
|
9
9
|
import {
|
|
10
10
|
useCreateNote,
|
|
11
11
|
useDeleteNote,
|
|
12
12
|
useNotesList,
|
|
13
13
|
useUpdateNote,
|
|
14
14
|
type Note,
|
|
15
|
-
} from '
|
|
15
|
+
} from '@/queries/notes';
|
|
16
16
|
|
|
17
17
|
const PAGE_SIZE = 20;
|
|
18
18
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router';
|
|
2
2
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
3
|
-
import {
|
|
3
|
+
import { SyntheticEvent, useEffect, useState } from 'react';
|
|
4
4
|
import { useDraft, useNotify, useAuthStore } from '@icore/template-shared';
|
|
5
|
-
import { PageLayout } from '
|
|
6
|
-
import { Button } from '
|
|
7
|
-
import { Input } from '
|
|
8
|
-
import { Label } from '
|
|
9
|
-
import { api } from '
|
|
5
|
+
import { PageLayout } from '@/components/PageLayout';
|
|
6
|
+
import { Button } from '@/components/ui/button';
|
|
7
|
+
import { Input } from '@/components/ui/input';
|
|
8
|
+
import { Label } from '@/components/ui/label';
|
|
9
|
+
import { api } from '@/main';
|
|
10
10
|
|
|
11
11
|
interface ProfilePayload {
|
|
12
12
|
uid: string;
|
|
@@ -47,7 +47,7 @@ function ProfilePage() {
|
|
|
47
47
|
onError: (err) => notify.error(err instanceof Error ? err.message : 'save_failed'),
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
function handleSubmit(e:
|
|
50
|
+
function handleSubmit(e: SyntheticEvent<HTMLFormElement>) {
|
|
51
51
|
e.preventDefault();
|
|
52
52
|
save.mutate(name);
|
|
53
53
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
|
2
|
-
import {
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { useAuthStore, useNotify } from '@icore/template-shared';
|
|
5
|
-
import { api } from '../main';
|
|
6
|
-
import { Button } from '../components/ui/button';
|
|
7
|
-
import { Input } from '../components/ui/input';
|
|
8
|
-
import { Label } from '../components/ui/label';
|
|
9
|
-
import {
|
|
1
|
+
import { SyntheticEvent, createFileRoute, useNavigate } from '@tanstack/react-router';
|
|
2
|
+
import { SyntheticEvent, useState } from 'react';
|
|
3
|
+
import { SyntheticEvent, useTranslation } from 'react-i18next';
|
|
4
|
+
import { SyntheticEvent, useAuthStore, useNotify } from '@icore/template-shared';
|
|
5
|
+
import { SyntheticEvent, api } from '../main';
|
|
6
|
+
import { SyntheticEvent, Button } from '../components/ui/button';
|
|
7
|
+
import { SyntheticEvent, Input } from '../components/ui/input';
|
|
8
|
+
import { SyntheticEvent, Label } from '../components/ui/label';
|
|
9
|
+
import {
|
|
10
|
+
SyntheticEvent,
|
|
11
|
+
Card,
|
|
12
|
+
CardContent,
|
|
13
|
+
CardDescription,
|
|
14
|
+
CardHeader,
|
|
15
|
+
CardTitle,
|
|
16
|
+
} from '../components/ui/card';
|
|
10
17
|
|
|
11
18
|
type Mode = 'password' | 'magicLinkRequest' | 'magicLinkSent';
|
|
12
19
|
|
|
@@ -21,7 +28,7 @@ function LoginPage() {
|
|
|
21
28
|
const [password, setPassword] = useState('');
|
|
22
29
|
const [submitting, setSubmitting] = useState(false);
|
|
23
30
|
|
|
24
|
-
async function handlePasswordSubmit(e:
|
|
31
|
+
async function handlePasswordSubmit(e: SyntheticEvent<HTMLFormElement>) {
|
|
25
32
|
e.preventDefault();
|
|
26
33
|
setSubmitting(true);
|
|
27
34
|
try {
|
|
@@ -36,7 +43,7 @@ function LoginPage() {
|
|
|
36
43
|
});
|
|
37
44
|
setAuth(session);
|
|
38
45
|
notify.success(t('auth.login'));
|
|
39
|
-
await navigate({ to: '/
|
|
46
|
+
await navigate({ to: '/dashboard' });
|
|
40
47
|
} catch (err) {
|
|
41
48
|
notify.error(err instanceof Error ? err.message : t('error.unknown'));
|
|
42
49
|
} finally {
|
|
@@ -44,7 +51,7 @@ function LoginPage() {
|
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
async function handleMagicLinkSubmit(e:
|
|
54
|
+
async function handleMagicLinkSubmit(e: SyntheticEvent<HTMLFormElement>) {
|
|
48
55
|
e.preventDefault();
|
|
49
56
|
setSubmitting(true);
|
|
50
57
|
try {
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
"esModuleInterop": false,
|
|
9
9
|
"allowSyntheticDefaultImports": true,
|
|
10
10
|
"strict": true,
|
|
11
|
-
"types": ["vite/client", "vitest"]
|
|
11
|
+
"types": ["vite/client", "vitest"],
|
|
12
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
13
|
+
"paths": {
|
|
14
|
+
"@/*": ["./src/*"]
|
|
15
|
+
},
|
|
16
|
+
"baseUrl": "."
|
|
12
17
|
},
|
|
13
18
|
"files": [],
|
|
14
19
|
"include": [],
|