create-carlonicora-app 1.0.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/LICENSE +675 -0
- package/README.md +104 -0
- package/bin/cli.js +3 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +92 -0
- package/dist/cli.js.map +1 -0
- package/dist/git.d.ts +7 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +80 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +5 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +30 -0
- package/dist/prompts.js.map +1 -0
- package/dist/replacer.d.ts +9 -0
- package/dist/replacer.d.ts.map +1 -0
- package/dist/replacer.js +11 -0
- package/dist/replacer.js.map +1 -0
- package/dist/scaffold.d.ts +3 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +79 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/files.d.ts +6 -0
- package/dist/utils/files.d.ts.map +1 -0
- package/dist/utils/files.js +103 -0
- package/dist/utils/files.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +35 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +6 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +63 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +52 -0
- package/template/.env.example +159 -0
- package/template/.github/workflows/check-library-updates.yml +71 -0
- package/template/.github/workflows/dev.yml +63 -0
- package/template/.github/workflows/pull-request.yml +55 -0
- package/template/.gitmodules +6 -0
- package/template/.husky/pre-commit +1 -0
- package/template/.husky/pre-push +1 -0
- package/template/.prettierignore +1 -0
- package/template/.prettierrc +13 -0
- package/template/.releaserc +134 -0
- package/template/.vscode/settings.json +16 -0
- package/template/CHANGELOG.md +0 -0
- package/template/CLAUDE.md +34 -0
- package/template/DOCKER.md +1591 -0
- package/template/Dockerfile +228 -0
- package/template/README.md +1 -0
- package/template/apps/api/.prettierrc +12 -0
- package/template/apps/api/eslint.config.mjs +54 -0
- package/template/apps/api/jest.config.js +29 -0
- package/template/apps/api/nest-cli.json +15 -0
- package/template/apps/api/package.json +155 -0
- package/template/apps/api/src/config/config.ts +17 -0
- package/template/apps/api/src/config/enums/job.name.ts +6 -0
- package/template/apps/api/src/config/enums/queue.id.ts +3 -0
- package/template/apps/api/src/config/interfaces/config.interface.ts +3 -0
- package/template/apps/api/src/features/features.modules.ts +6 -0
- package/template/apps/api/src/i18n/en/notifications.json +3 -0
- package/template/apps/api/src/main.ts +23 -0
- package/template/apps/api/src/neo4j.migrations/20250901_001.ts +33 -0
- package/template/apps/api/src/neo4j.migrations/20250901_002.ts +90 -0
- package/template/apps/api/src/neo4j.migrations/20250901_003.ts +57 -0
- package/template/apps/api/src/neo4j.migrations/20250901_004.ts +32 -0
- package/template/apps/api/src/neo4j.migrations/queries/migration.queries.ts +49 -0
- package/template/apps/api/src/types/langchain.d.ts +56 -0
- package/template/apps/api/tsconfig.build.json +4 -0
- package/template/apps/api/tsconfig.json +38 -0
- package/template/apps/web/.swcrc +26 -0
- package/template/apps/web/components.json +21 -0
- package/template/apps/web/eslint.config.mjs +33 -0
- package/template/apps/web/global.d.ts +7 -0
- package/template/apps/web/messages/en.json +249 -0
- package/template/apps/web/next.config.js +50 -0
- package/template/apps/web/package.json +146 -0
- package/template/apps/web/playwright.config.ts +86 -0
- package/template/apps/web/postcss.config.mjs +5 -0
- package/template/apps/web/public/sw.js +32 -0
- package/template/apps/web/src/app/[locale]/(admin)/administration/companies/[id]/page.tsx +46 -0
- package/template/apps/web/src/app/[locale]/(admin)/administration/companies/page.tsx +23 -0
- package/template/apps/web/src/app/[locale]/(admin)/layout.tsx +49 -0
- package/template/apps/web/src/app/[locale]/(auth)/activation/[code]/page.tsx +13 -0
- package/template/apps/web/src/app/[locale]/(auth)/auth/page.tsx +11 -0
- package/template/apps/web/src/app/[locale]/(auth)/invitation/[code]/page.tsx +7 -0
- package/template/apps/web/src/app/[locale]/(auth)/layout.tsx +9 -0
- package/template/apps/web/src/app/[locale]/(auth)/login/page.tsx +6 -0
- package/template/apps/web/src/app/[locale]/(auth)/logout/page.tsx +5 -0
- package/template/apps/web/src/app/[locale]/(auth)/register/page.tsx +6 -0
- package/template/apps/web/src/app/[locale]/(auth)/reset/[code]/page.tsx +7 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/notifications/page.tsx +9 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/[id]/page.tsx +23 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/roles/page.tsx +12 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/error.tsx +14 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/loading.tsx +21 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/[id]/page.tsx +46 -0
- package/template/apps/web/src/app/[locale]/(main)/(foundations)/users/page.tsx +17 -0
- package/template/apps/web/src/app/[locale]/(main)/error.tsx +62 -0
- package/template/apps/web/src/app/[locale]/(main)/layout.tsx +40 -0
- package/template/apps/web/src/app/[locale]/(main)/page.tsx +41 -0
- package/template/apps/web/src/app/[locale]/layout.tsx +54 -0
- package/template/apps/web/src/app/globals.css +256 -0
- package/template/apps/web/src/config/BootstrapProvider.tsx +13 -0
- package/template/apps/web/src/config/Bootstrapper.ts +77 -0
- package/template/apps/web/src/config/env.ts +51 -0
- package/template/apps/web/src/config/middleware-env.ts +14 -0
- package/template/apps/web/src/enums/feature.ids.ts +3 -0
- package/template/apps/web/src/features/common/components/containers/IndexContainer.tsx +11 -0
- package/template/apps/web/src/features/common/components/details/LayoutDetails.tsx +33 -0
- package/template/apps/web/src/features/common/components/navigations/CommonSidebar.tsx +233 -0
- package/template/apps/web/src/features/common/components/navigations/CreationDropDown.tsx +117 -0
- package/template/apps/web/src/features/common/components/navigations/UserSidebarFooter.tsx +115 -0
- package/template/apps/web/src/features/common/components/navigations/VersionDisplay.tsx +18 -0
- package/template/apps/web/src/features/common/contexts/ErrorContext.tsx +62 -0
- package/template/apps/web/src/i18n/request.ts +13 -0
- package/template/apps/web/src/i18n/routing.ts +9 -0
- package/template/apps/web/src/i18n/useDateFnsLocale.ts +15 -0
- package/template/apps/web/src/proxy.ts +107 -0
- package/template/apps/web/src/server-actions/auth-cookies.ts +134 -0
- package/template/apps/web/src/types/modules.d.ts +10 -0
- package/template/apps/web/src/utils/metadata.ts +50 -0
- package/template/apps/web/src/utils/revalidation.ts +7 -0
- package/template/apps/web/tsconfig.json +51 -0
- package/template/docker-compose.yml +211 -0
- package/template/package.json +72 -0
- package/template/packages/nestjs-neo4jsonapi/.gitkeep +0 -0
- package/template/packages/nextjs-jsonapi/.gitkeep +0 -0
- package/template/packages/shared/package.json +23 -0
- package/template/packages/shared/src/const/roles.id.ts +5 -0
- package/template/packages/shared/src/const/system.roles.id.ts +4 -0
- package/template/packages/shared/src/index.ts +1 -0
- package/template/packages/shared/tsconfig.json +10 -0
- package/template/packages/shared/tsup.config.ts +16 -0
- package/template/pnpm-workspace.yaml +3 -0
- package/template/tsconfig.base.json +62 -0
- package/template/tsconfig.json +12 -0
- package/template/turbo.json +88 -0
- package/template/versions.production.json +4 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
const createNextIntlPlugin = require("next-intl/plugin");
|
|
4
|
+
|
|
5
|
+
// Try pointing to package's request config (requires next-intl to resolve module specifiers)
|
|
6
|
+
// Note: If this doesn't work, we'll need a minimal ./src/i18n/request.ts file
|
|
7
|
+
const withNextIntl = createNextIntlPlugin();
|
|
8
|
+
|
|
9
|
+
const imageSources = process.env.IMAGE_SOURCES
|
|
10
|
+
? process.env.IMAGE_SOURCES.split(",").map((url) => {
|
|
11
|
+
const { hostname, protocol, port } = new URL(url.trim());
|
|
12
|
+
return {
|
|
13
|
+
protocol: protocol.replace(":", ""),
|
|
14
|
+
hostname,
|
|
15
|
+
port: port || undefined,
|
|
16
|
+
};
|
|
17
|
+
})
|
|
18
|
+
: [];
|
|
19
|
+
|
|
20
|
+
/** @type {import('next').NextConfig} */
|
|
21
|
+
const nextConfig = {
|
|
22
|
+
experimental: {
|
|
23
|
+
useCache: true,
|
|
24
|
+
serverActions: {
|
|
25
|
+
bodySizeLimit: "5mb",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
pageExtensions: ["ts", "tsx"],
|
|
29
|
+
images: {
|
|
30
|
+
minimumCacheTTL: 60,
|
|
31
|
+
remotePatterns: imageSources,
|
|
32
|
+
dangerouslyAllowLocalIP: true,
|
|
33
|
+
},
|
|
34
|
+
reactStrictMode: false,
|
|
35
|
+
env: {
|
|
36
|
+
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL ?? "",
|
|
37
|
+
NEXT_PUBLIC_ADDRESS: process.env.NEXT_PUBLIC_ADDRESS ?? "",
|
|
38
|
+
NEXT_PUBLIC_VAPID_PUBLIC_KEY: process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY ?? "",
|
|
39
|
+
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY ?? "",
|
|
40
|
+
},
|
|
41
|
+
webpack: (config, { isServer }) => {
|
|
42
|
+
// Force single Yjs instance to prevent "Yjs was already imported" error
|
|
43
|
+
// Note: This only works with webpack builds (production). For Turbopack (dev),
|
|
44
|
+
// we rely on pnpm.overrides in root package.json
|
|
45
|
+
config.resolve.alias["yjs"] = path.resolve(__dirname, "node_modules/yjs");
|
|
46
|
+
return config;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
module.exports = withNextIntl(nextConfig);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}-web",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "dotenv -e ../../.env -- next build",
|
|
7
|
+
"dev": "dotenv -e ../../.env -- next dev",
|
|
8
|
+
"lint": "eslint .",
|
|
9
|
+
"start": "dotenv -e ../../.env -- next start -H 0.0.0.0",
|
|
10
|
+
"test": "jest",
|
|
11
|
+
"test:coverage": "jest --coverage",
|
|
12
|
+
"test:watch": "jest --watchAll --verbose",
|
|
13
|
+
"test:e2e": "playwright test",
|
|
14
|
+
"test:e2e:ui": "playwright test --ui",
|
|
15
|
+
"test:e2e:debug": "playwright test --debug",
|
|
16
|
+
"format": "prettier --write .",
|
|
17
|
+
"typecheck": "eslint ."
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": "22"
|
|
21
|
+
},
|
|
22
|
+
"packageManager": "pnpm@10.25.0",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@aws-sdk/lib-storage": "^3.948.0",
|
|
25
|
+
"@aws-sdk/s3-request-presigner": "^3.948.0",
|
|
26
|
+
"@aws-sdk/xhr-http-handler": "^3.936.0",
|
|
27
|
+
"@dnd-kit/core": "^6.3.1",
|
|
28
|
+
"@dnd-kit/modifiers": "^9.0.0",
|
|
29
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
30
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
31
|
+
"@floating-ui/react": "^0.27.16",
|
|
32
|
+
"@hello-pangea/dnd": "^18.0.1",
|
|
33
|
+
"@hookform/resolvers": "^5.2.2",
|
|
34
|
+
"@next/third-parties": "16.0.10",
|
|
35
|
+
"@carlonicora/nextjs-jsonapi": "1.1.1",
|
|
36
|
+
"@{{name}}/shared": "workspace:*",
|
|
37
|
+
"@radix-ui/react-accordion": "^1.2.12",
|
|
38
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
39
|
+
"@radix-ui/react-avatar": "^1.1.11",
|
|
40
|
+
"@radix-ui/react-checkbox": "^1.3.3",
|
|
41
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
42
|
+
"@radix-ui/react-context-menu": "^2.2.16",
|
|
43
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
44
|
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
45
|
+
"@radix-ui/react-focus-scope": "^1.1.8",
|
|
46
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
47
|
+
"@radix-ui/react-icons": "^1.3.2",
|
|
48
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
49
|
+
"@radix-ui/react-navigation-menu": "^1.2.14",
|
|
50
|
+
"@radix-ui/react-popover": "^1.1.15",
|
|
51
|
+
"@radix-ui/react-progress": "^1.1.8",
|
|
52
|
+
"@radix-ui/react-radio-group": "^1.3.8",
|
|
53
|
+
"@radix-ui/react-scroll-area": "^1.2.10",
|
|
54
|
+
"@radix-ui/react-select": "^2.2.6",
|
|
55
|
+
"@radix-ui/react-separator": "^1.1.8",
|
|
56
|
+
"@radix-ui/react-slider": "^1.3.6",
|
|
57
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
58
|
+
"@radix-ui/react-switch": "^1.2.6",
|
|
59
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
60
|
+
"@radix-ui/react-toast": "^1.2.15",
|
|
61
|
+
"@radix-ui/react-toggle": "^1.1.10",
|
|
62
|
+
"@radix-ui/react-tooltip": "^1.2.8",
|
|
63
|
+
"@tanstack/react-table": "^8.21.3",
|
|
64
|
+
"autoprefixer": "^10.4.22",
|
|
65
|
+
"class-variance-authority": "^0.7.1",
|
|
66
|
+
"clsx": "^2.1.1",
|
|
67
|
+
"cmdk": "^1.1.1",
|
|
68
|
+
"codice-fiscale-js": "^2.3.23",
|
|
69
|
+
"cookies-next": "^6.1.1",
|
|
70
|
+
"date-fns": "^4.1.0",
|
|
71
|
+
"embla-carousel-react": "^8.6.0",
|
|
72
|
+
"framer-motion": "^12.23.26",
|
|
73
|
+
"fs": "^0.0.1-security",
|
|
74
|
+
"fuse.js": "^7.1.0",
|
|
75
|
+
"i18n-iso-countries": "^7.14.0",
|
|
76
|
+
"i18next": "^25.7.2",
|
|
77
|
+
"jotai": "^2.16.0",
|
|
78
|
+
"jsonwebtoken": "^9.0.3",
|
|
79
|
+
"jszip": "^3.10.1",
|
|
80
|
+
"lodash": "^4.17.21",
|
|
81
|
+
"lucide": "^0.561.0",
|
|
82
|
+
"lucide-react": "^0.561.0",
|
|
83
|
+
"mailparser": "^3.9.1",
|
|
84
|
+
"mammoth": "^1.11.0",
|
|
85
|
+
"next": "16.0.10",
|
|
86
|
+
"next-intl": "^4.5.8",
|
|
87
|
+
"next-share": "^0.27.0",
|
|
88
|
+
"next-themes": "^0.4.6",
|
|
89
|
+
"papaparse": "^5.5.3",
|
|
90
|
+
"pdfjs-dist": "^5.4.449",
|
|
91
|
+
"postal-mime": "^2.6.1",
|
|
92
|
+
"react": "19.2.3",
|
|
93
|
+
"react-cookie": "8.0.1",
|
|
94
|
+
"react-day-picker": "^9.12.0",
|
|
95
|
+
"react-dom": "19.2.3",
|
|
96
|
+
"react-dropzone": "^14.3.8",
|
|
97
|
+
"react-easy-swipe": "^0.0.23",
|
|
98
|
+
"react-hook-form": "^7.68.0",
|
|
99
|
+
"react-horizontal-scrolling-menu": "^8.2.0",
|
|
100
|
+
"react-i18next": "^16.5.0",
|
|
101
|
+
"react-spinners": "^0.17.0",
|
|
102
|
+
"react-toastify": "^11.0.5",
|
|
103
|
+
"recharts": "^3.5.1",
|
|
104
|
+
"sharp": "^0.34.5",
|
|
105
|
+
"socket.io-client": "^4.8.1",
|
|
106
|
+
"sonner": "^2.0.7",
|
|
107
|
+
"tailwind-merge": "^3.4.0",
|
|
108
|
+
"tailwindcss": "^4.1.18",
|
|
109
|
+
"tailwindcss-animate": "^1.0.7",
|
|
110
|
+
"turndown": "^7.2.2",
|
|
111
|
+
"uuid": "^13.0.0",
|
|
112
|
+
"vaul": "^1.1.2",
|
|
113
|
+
"xlsx-republish": "^0.20.3",
|
|
114
|
+
"yjs": "^13.6.27"
|
|
115
|
+
},
|
|
116
|
+
"devDependencies": {
|
|
117
|
+
"@next/eslint-plugin-next": "16.0.10",
|
|
118
|
+
"@playwright/test": "^1.57.0",
|
|
119
|
+
"@tailwindcss/postcss": "^4",
|
|
120
|
+
"@testing-library/dom": "^10.4.1",
|
|
121
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
122
|
+
"@testing-library/react": "^16.3.0",
|
|
123
|
+
"@testing-library/user-event": "^14.6.1",
|
|
124
|
+
"@types/accept-language-parser": "^1.5.8",
|
|
125
|
+
"@types/google.maps": "^3.58.1",
|
|
126
|
+
"@types/jest": "^30.0.0",
|
|
127
|
+
"@types/jsonwebtoken": "^9.0.10",
|
|
128
|
+
"@types/katex": "^0.16.7",
|
|
129
|
+
"@types/lodash": "^4.17.21",
|
|
130
|
+
"@types/mailparser": "^3.4.6",
|
|
131
|
+
"@types/negotiator": "^0.6.4",
|
|
132
|
+
"@types/papaparse": "^5.5.1",
|
|
133
|
+
"@types/react": "19.2.7",
|
|
134
|
+
"@types/react-dom": "19.2.3",
|
|
135
|
+
"@types/turndown": "^5.0.6",
|
|
136
|
+
"dotenv": "^17.2.3",
|
|
137
|
+
"eslint": "^9.39.1",
|
|
138
|
+
"eslint-config-next": "16.0.10",
|
|
139
|
+
"eslint-plugin-react": "^7.37.5",
|
|
140
|
+
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
141
|
+
"sass-loader": "^16.0.6",
|
|
142
|
+
"ts-jest": "^29.4.6",
|
|
143
|
+
"ts-node": "^10.9.2",
|
|
144
|
+
"tw-animate-css": "^1.4.0"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read environment variables from file.
|
|
5
|
+
* https://github.com/motdotla/dotenv
|
|
6
|
+
*/
|
|
7
|
+
import dotenv from "dotenv";
|
|
8
|
+
import path from "path";
|
|
9
|
+
dotenv.config({ path: path.resolve(__dirname, ".env") });
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
13
|
+
*/
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
testDir: "./tests",
|
|
16
|
+
/* Run tests in files in parallel */
|
|
17
|
+
fullyParallel: true,
|
|
18
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
19
|
+
forbidOnly: !!process.env.CI,
|
|
20
|
+
/* Retry on CI only */
|
|
21
|
+
retries: process.env.CI ? 2 : 0,
|
|
22
|
+
/* Opt out of parallel tests on CI. */
|
|
23
|
+
workers: process.env.CI ? 1 : undefined,
|
|
24
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
25
|
+
reporter: "html",
|
|
26
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
27
|
+
use: {
|
|
28
|
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
29
|
+
baseURL: `http://localhost:${process.env.PORT || 3000}`,
|
|
30
|
+
|
|
31
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
32
|
+
trace: "on-first-retry",
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/* Configure projects for major browsers */
|
|
36
|
+
projects: [
|
|
37
|
+
// Setup project
|
|
38
|
+
{ name: "setup", testMatch: /.*\.setup\.ts/ },
|
|
39
|
+
|
|
40
|
+
// Unauthenticated tests
|
|
41
|
+
{
|
|
42
|
+
name: "chromium-unauth",
|
|
43
|
+
use: { ...devices["Desktop Chrome"] },
|
|
44
|
+
testDir: "./tests/unauthenticated",
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Authenticated tests
|
|
48
|
+
{
|
|
49
|
+
name: "chromium-auth",
|
|
50
|
+
use: {
|
|
51
|
+
...devices["Desktop Chrome"],
|
|
52
|
+
storageState: "playwright/.auth/user.json",
|
|
53
|
+
},
|
|
54
|
+
dependencies: ["setup"],
|
|
55
|
+
testDir: "./tests/authenticated",
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/* Test against viewports. */
|
|
59
|
+
// {
|
|
60
|
+
// name: 'Mobile Chrome',
|
|
61
|
+
// use: { ...devices['Pixel 5'] },
|
|
62
|
+
// },
|
|
63
|
+
// {
|
|
64
|
+
// name: 'Mobile Safari',
|
|
65
|
+
// use: { ...devices['iPhone 12'] },
|
|
66
|
+
// },
|
|
67
|
+
|
|
68
|
+
/* Test against branded browsers. */
|
|
69
|
+
// {
|
|
70
|
+
// name: 'Microsoft Edge',
|
|
71
|
+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
72
|
+
// },
|
|
73
|
+
// {
|
|
74
|
+
// name: 'Google Chrome',
|
|
75
|
+
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
76
|
+
// },
|
|
77
|
+
],
|
|
78
|
+
|
|
79
|
+
/* Run your local dev server before starting the tests */
|
|
80
|
+
webServer: {
|
|
81
|
+
command: "npm run dev",
|
|
82
|
+
url: `http://localhost:${process.env.PORT || 3000}`,
|
|
83
|
+
reuseExistingServer: true,
|
|
84
|
+
timeout: 120 * 1000,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
self.addEventListener("push", function (event) {
|
|
2
|
+
var data = event.data ? event.data.json() : {};
|
|
3
|
+
var title = data.title || "Notification";
|
|
4
|
+
var options = {
|
|
5
|
+
body: data.message || "You have a new notification",
|
|
6
|
+
icon: "/{{name}}-logo.webp",
|
|
7
|
+
data: data.url,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
event.waitUntil(self.registration.showNotification(title, options));
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
self.addEventListener("notificationclick", function (event) {
|
|
14
|
+
event.notification.close();
|
|
15
|
+
event.waitUntil(
|
|
16
|
+
(async function () {
|
|
17
|
+
var clientList = await self.clients.matchAll({
|
|
18
|
+
type: "window",
|
|
19
|
+
includeUncontrolled: true,
|
|
20
|
+
});
|
|
21
|
+
for (var i = 0; i < clientList.length; i++) {
|
|
22
|
+
var windowClient = clientList[i];
|
|
23
|
+
if (windowClient.url === event.notification.data && "focus" in windowClient) {
|
|
24
|
+
return windowClient.focus();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (self.clients.openWindow && event.notification.data) {
|
|
28
|
+
return self.clients.openWindow(event.notification.data);
|
|
29
|
+
}
|
|
30
|
+
})(),
|
|
31
|
+
);
|
|
32
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateSpecificMetadata } from "@/utils/metadata";
|
|
2
|
+
import { AdminCompanyContainer, PageContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
3
|
+
import { CompanyProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
4
|
+
import { Modules } from "@carlonicora/nextjs-jsonapi/core";
|
|
5
|
+
import { CompanyInterface, CompanyService } from "@carlonicora/nextjs-jsonapi/features";
|
|
6
|
+
import { Action } from "@carlonicora/nextjs-jsonapi/permissions";
|
|
7
|
+
import { ServerSession } from "@carlonicora/nextjs-jsonapi/server";
|
|
8
|
+
import { RoleId } from "@{{name}}/shared";
|
|
9
|
+
import { Metadata } from "next";
|
|
10
|
+
import { getTranslations } from "next-intl/server";
|
|
11
|
+
import { cache } from "react";
|
|
12
|
+
|
|
13
|
+
const getCachedCompany = cache(async (id: string) => CompanyService.findOne({ companyId: id }));
|
|
14
|
+
|
|
15
|
+
export async function generateMetadata(props: { params: Promise<{ id: string }> }): Promise<Metadata> {
|
|
16
|
+
const params = await props.params;
|
|
17
|
+
const t = await getTranslations();
|
|
18
|
+
|
|
19
|
+
const company: CompanyInterface = await getCachedCompany(params.id);
|
|
20
|
+
|
|
21
|
+
const title = (await ServerSession.hasPermissionToModule({
|
|
22
|
+
module: Modules.Company,
|
|
23
|
+
action: Action.Read,
|
|
24
|
+
data: company,
|
|
25
|
+
}))
|
|
26
|
+
? `[${t(`types.companies`, { count: 1 })}] ${company.name}`
|
|
27
|
+
: `${t(`types.companies`, { count: 1 })}`;
|
|
28
|
+
|
|
29
|
+
return await generateSpecificMetadata({ title: title });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default async function CompanyPage(props: { params: Promise<{ id: string }> }) {
|
|
33
|
+
const params = await props.params;
|
|
34
|
+
const company: CompanyInterface = await getCachedCompany(params.id);
|
|
35
|
+
|
|
36
|
+
if (!(await ServerSession.hasRole(RoleId.Administrator)))
|
|
37
|
+
ServerSession.checkPermission({ module: Modules.Company, action: Action.Read, data: company });
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<CompanyProvider dehydratedCompany={company.dehydrate()}>
|
|
41
|
+
<PageContainer>
|
|
42
|
+
<AdminCompanyContainer />
|
|
43
|
+
</PageContainer>
|
|
44
|
+
</CompanyProvider>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { generateSpecificMetadata } from "@/utils/metadata";
|
|
2
|
+
import { CompaniesList, PageContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
3
|
+
import { CompanyProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
4
|
+
import { Metadata } from "next";
|
|
5
|
+
import { getTranslations } from "next-intl/server";
|
|
6
|
+
|
|
7
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
8
|
+
const t = await getTranslations();
|
|
9
|
+
|
|
10
|
+
return await generateSpecificMetadata({
|
|
11
|
+
title: t(`types.companies`, { count: 2 }),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default async function CompaniesListPage() {
|
|
16
|
+
return (
|
|
17
|
+
<CompanyProvider>
|
|
18
|
+
<PageContainer>
|
|
19
|
+
<CompaniesList />
|
|
20
|
+
</PageContainer>
|
|
21
|
+
</CompanyProvider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ServerSession } from "@carlonicora/nextjs-jsonapi/server";
|
|
2
|
+
import "react-horizontal-scrolling-menu/dist/styles.css";
|
|
3
|
+
|
|
4
|
+
import LayoutDetails from "@/features/common/components/details/LayoutDetails";
|
|
5
|
+
import { routing } from "@/i18n/routing";
|
|
6
|
+
import { PushNotificationProvider, RefreshUser } from "@carlonicora/nextjs-jsonapi/components";
|
|
7
|
+
import { NotificationContextProvider, SocketProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
8
|
+
import { SidebarProvider } from "@carlonicora/nextjs-jsonapi/shadcnui";
|
|
9
|
+
import { hasLocale } from "next-intl";
|
|
10
|
+
import { getMessages, setRequestLocale } from "next-intl/server";
|
|
11
|
+
import { Inter } from "next/font/google";
|
|
12
|
+
import { cookies } from "next/headers";
|
|
13
|
+
import { notFound } from "next/navigation";
|
|
14
|
+
import "../../globals.css";
|
|
15
|
+
|
|
16
|
+
const fontSans = Inter({ subsets: ["latin"], weight: ["100", "300", "400", "700"], variable: "--font-sans" });
|
|
17
|
+
|
|
18
|
+
export default async function AdminLayout(props: { children: React.ReactNode; params: Promise<{ locale: string }> }) {
|
|
19
|
+
const params = await props.params;
|
|
20
|
+
|
|
21
|
+
const { locale } = params;
|
|
22
|
+
const { children } = props;
|
|
23
|
+
|
|
24
|
+
if (!hasLocale(routing.locales, locale)) {
|
|
25
|
+
notFound();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const cookieStore = await cookies();
|
|
29
|
+
const token = cookieStore.get("token")?.value;
|
|
30
|
+
setRequestLocale(locale);
|
|
31
|
+
const messages = await getMessages();
|
|
32
|
+
const defaultOpen = cookieStore.get("sidebar_state")?.value === "true";
|
|
33
|
+
|
|
34
|
+
if (await ServerSession.isLogged())
|
|
35
|
+
return (
|
|
36
|
+
<SocketProvider token={token}>
|
|
37
|
+
<PushNotificationProvider>
|
|
38
|
+
<NotificationContextProvider>
|
|
39
|
+
<SidebarProvider defaultOpen={defaultOpen}>
|
|
40
|
+
<RefreshUser />
|
|
41
|
+
<LayoutDetails>{children}</LayoutDetails>
|
|
42
|
+
</SidebarProvider>
|
|
43
|
+
</NotificationContextProvider>
|
|
44
|
+
</PushNotificationProvider>
|
|
45
|
+
</SocketProvider>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return <div className="flex min-h-screen w-full flex-col items-center justify-center">{children}</div>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { generateSpecificMetadata } from "@/utils/metadata";
|
|
2
|
+
import { AuthContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
3
|
+
import { AuthComponent } from "@carlonicora/nextjs-jsonapi/features";
|
|
4
|
+
import { Metadata } from "next";
|
|
5
|
+
|
|
6
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
7
|
+
return await generateSpecificMetadata({});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default async function ActivatePage(props: { params: Promise<{ code: string }> }) {
|
|
11
|
+
const params = await props.params;
|
|
12
|
+
return <AuthContainer componentType={AuthComponent.ActivateAccount} params={{ code: params.code }} />;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Cookies } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
import { AuthInterface, AuthService } from "@carlonicora/nextjs-jsonapi/features";
|
|
3
|
+
|
|
4
|
+
export default async function AuthPage(props: { searchParams: Promise<{ code: string }> }) {
|
|
5
|
+
const searchParams = await props.searchParams;
|
|
6
|
+
const auth: AuthInterface = await AuthService.findToken({
|
|
7
|
+
tokenCode: searchParams.code,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return <Cookies dehydratedAuth={auth.dehydrate()} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AuthContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
import { AuthComponent } from "@carlonicora/nextjs-jsonapi/features";
|
|
3
|
+
|
|
4
|
+
export default async function InvitationPage(props: { params: Promise<{ code: string }> }) {
|
|
5
|
+
const params = await props.params;
|
|
6
|
+
return <AuthContainer componentType={AuthComponent.AcceptInvitation} params={{ code: params.code }} />;
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default async function MainLayout(props: { children: React.ReactNode; params: Promise<{ locale: string }> }) {
|
|
2
|
+
const { children } = props;
|
|
3
|
+
|
|
4
|
+
return (
|
|
5
|
+
<div data-wrapper className="flex h-screen w-full items-center justify-center">
|
|
6
|
+
{children}
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AuthContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
import { AuthComponent } from "@carlonicora/nextjs-jsonapi/features";
|
|
3
|
+
|
|
4
|
+
export default async function ResetPage(props: { params: Promise<{ code: string }> }) {
|
|
5
|
+
const params = await props.params;
|
|
6
|
+
return <AuthContainer componentType={AuthComponent.ResetPassword} params={{ code: params.code }} />;
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NotificationsListContainer, PageContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
|
|
3
|
+
export default async function NotificationListPage() {
|
|
4
|
+
return (
|
|
5
|
+
<PageContainer testId="page-inbox-container">
|
|
6
|
+
<NotificationsListContainer />
|
|
7
|
+
</PageContainer>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PageContainer, RoleContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
import { RoleProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
3
|
+
import { Modules } from "@carlonicora/nextjs-jsonapi/core";
|
|
4
|
+
import { RoleInterface, RoleService } from "@carlonicora/nextjs-jsonapi/features";
|
|
5
|
+
import { Action } from "@carlonicora/nextjs-jsonapi/permissions";
|
|
6
|
+
import { ServerSession } from "@carlonicora/nextjs-jsonapi/server";
|
|
7
|
+
|
|
8
|
+
export default async function RolePage(props: { params: Promise<{ id: string }> }) {
|
|
9
|
+
const params = await props.params;
|
|
10
|
+
const role: RoleInterface = await RoleService.findById({
|
|
11
|
+
roleId: params.id,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
ServerSession.checkPermission({ module: Modules.Role, action: Action.Read, data: role });
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<RoleProvider dehydratedRole={role.dehydrate()}>
|
|
18
|
+
<PageContainer>
|
|
19
|
+
<RoleContainer />
|
|
20
|
+
</PageContainer>
|
|
21
|
+
</RoleProvider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PageContainer, RolesList } from "@carlonicora/nextjs-jsonapi/components";
|
|
2
|
+
import { RoleProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
3
|
+
|
|
4
|
+
export default async function RolesListPage() {
|
|
5
|
+
return (
|
|
6
|
+
<RoleProvider>
|
|
7
|
+
<PageContainer>
|
|
8
|
+
<RolesList />
|
|
9
|
+
</PageContainer>
|
|
10
|
+
</RoleProvider>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ErrorDetails, PageContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
3
|
+
import { UserProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
4
|
+
|
|
5
|
+
export default function ErrorPage({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
|
|
6
|
+
const customError = JSON.parse(error.message);
|
|
7
|
+
return (
|
|
8
|
+
<UserProvider>
|
|
9
|
+
<PageContainer>
|
|
10
|
+
<ErrorDetails code={customError.code ?? 500} message={customError.message ?? error} />
|
|
11
|
+
</PageContainer>
|
|
12
|
+
</UserProvider>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { PageContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
4
|
+
import { UserProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
5
|
+
import { Skeleton } from "@carlonicora/nextjs-jsonapi/shadcnui";
|
|
6
|
+
|
|
7
|
+
export default async function Loading() {
|
|
8
|
+
return (
|
|
9
|
+
<UserProvider>
|
|
10
|
+
<PageContainer>
|
|
11
|
+
<div className="flex h-full w-full flex-col items-center justify-center">
|
|
12
|
+
<Skeleton className="h-[125px] w-[250px] rounded-xl" />
|
|
13
|
+
<div className="space-y-2">
|
|
14
|
+
<Skeleton className="h-4 w-[250px]" />
|
|
15
|
+
<Skeleton className="h-4 w-[200px]" />
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</PageContainer>
|
|
19
|
+
</UserProvider>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateSpecificMetadata } from "@/utils/metadata";
|
|
2
|
+
import { PageContainer, UserContainer } from "@carlonicora/nextjs-jsonapi/components";
|
|
3
|
+
import { CompanyProvider, UserProvider } from "@carlonicora/nextjs-jsonapi/contexts";
|
|
4
|
+
import { Modules } from "@carlonicora/nextjs-jsonapi/core";
|
|
5
|
+
import { UserInterface, UserService } from "@carlonicora/nextjs-jsonapi/features";
|
|
6
|
+
import { Action } from "@carlonicora/nextjs-jsonapi/permissions";
|
|
7
|
+
import { ServerSession } from "@carlonicora/nextjs-jsonapi/server";
|
|
8
|
+
import { Metadata } from "next";
|
|
9
|
+
import { getTranslations } from "next-intl/server";
|
|
10
|
+
import { cache } from "react";
|
|
11
|
+
|
|
12
|
+
const getCachedUser = cache(async (id: string) => UserService.findById({ userId: id }));
|
|
13
|
+
|
|
14
|
+
export async function generateMetadata(props: { params: Promise<{ id: string }> }): Promise<Metadata> {
|
|
15
|
+
const params = await props.params;
|
|
16
|
+
const t = await getTranslations();
|
|
17
|
+
|
|
18
|
+
let title = `${t(`types.users`, { count: 1 })}`;
|
|
19
|
+
|
|
20
|
+
const user: UserInterface = (await getCachedUser(params.id)) as UserInterface;
|
|
21
|
+
|
|
22
|
+
if (await ServerSession.hasPermissionToModule({ module: Modules.User, action: Action.Read, data: user }))
|
|
23
|
+
title = `[${t(`types.users`, { count: 1 })}] ${user.name}`;
|
|
24
|
+
|
|
25
|
+
return await generateSpecificMetadata({ title: title });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default async function UserPage(props: {
|
|
29
|
+
params: Promise<{
|
|
30
|
+
id: string;
|
|
31
|
+
}>;
|
|
32
|
+
}) {
|
|
33
|
+
const params = await props.params;
|
|
34
|
+
|
|
35
|
+
const user: UserInterface = await getCachedUser(params.id);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<CompanyProvider dehydratedCompany={user.company?.dehydrate()}>
|
|
39
|
+
<UserProvider dehydratedUser={user.dehydrate()}>
|
|
40
|
+
<PageContainer>
|
|
41
|
+
<UserContainer />
|
|
42
|
+
</PageContainer>
|
|
43
|
+
</UserProvider>
|
|
44
|
+
</CompanyProvider>
|
|
45
|
+
);
|
|
46
|
+
}
|