create-ej-app 1.0.0 → 2.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.
Files changed (198) hide show
  1. package/cli.js +21 -3
  2. package/package.json +1 -1
  3. package/template/{.env.example → advanced/.env.example} +4 -0
  4. package/template/{components.json → advanced/components.json} +1 -1
  5. package/template/{package.json → advanced/package.json} +11 -0
  6. package/template/{prisma → advanced/prisma}/schema.prisma +18 -1
  7. package/template/{src → advanced/src}/app/(app)/tasks/[id]/actions.ts +46 -4
  8. package/template/{src → advanced/src}/app/(app)/tasks/[id]/render.tsx +136 -25
  9. package/template/{src → advanced/src}/app/(app)/tasks/actions.ts +0 -6
  10. package/template/{src → advanced/src}/app/(app)/tasks/page.tsx +0 -3
  11. package/template/{src → advanced/src}/app/(app)/tasks/render.tsx +0 -10
  12. package/template/advanced/src/app/api/upload/route.ts +45 -0
  13. package/template/{src → advanced/src}/app/layout.tsx +1 -1
  14. package/template/{src → advanced/src}/env.mjs +10 -2
  15. package/template/advanced/src/styles/editor.css +61 -0
  16. package/template/{tailwind.config.ts → advanced/tailwind.config.ts} +1 -1
  17. package/template/base/.env.example +16 -0
  18. package/template/base/.eslintrc.cjs +24 -0
  19. package/template/base/components.json +16 -0
  20. package/template/base/next.config.mjs +18 -0
  21. package/template/base/package.json +79 -0
  22. package/template/base/postcss.config.cjs +6 -0
  23. package/template/base/prettier.config.ts +11 -0
  24. package/template/base/prisma/schema.prisma +115 -0
  25. package/template/base/public/next.svg +1 -0
  26. package/template/base/src/app/(app)/dashboard/page.tsx +19 -0
  27. package/template/base/src/app/(app)/layout.tsx +90 -0
  28. package/template/base/src/app/(app)/settings/actions.ts +18 -0
  29. package/template/base/src/app/(app)/settings/loading.tsx +28 -0
  30. package/template/base/src/app/(app)/settings/page.tsx +28 -0
  31. package/template/base/src/app/(app)/settings/render.tsx +113 -0
  32. package/template/base/src/app/(app)/tasks/[id]/actions.ts +149 -0
  33. package/template/base/src/app/(app)/tasks/[id]/page.tsx +25 -0
  34. package/template/base/src/app/(app)/tasks/[id]/render.tsx +413 -0
  35. package/template/base/src/app/(app)/tasks/actions.ts +69 -0
  36. package/template/base/src/app/(app)/tasks/page.tsx +53 -0
  37. package/template/base/src/app/(app)/tasks/render.tsx +107 -0
  38. package/template/base/src/app/(app)/users/[id]/actions.ts +83 -0
  39. package/template/base/src/app/(app)/users/[id]/page.tsx +32 -0
  40. package/template/base/src/app/(app)/users/[id]/render.tsx +240 -0
  41. package/template/base/src/app/(app)/users/actions.ts +55 -0
  42. package/template/base/src/app/(app)/users/page.tsx +49 -0
  43. package/template/base/src/app/(app)/users/render.tsx +80 -0
  44. package/template/base/src/app/(auth)/layout.tsx +20 -0
  45. package/template/base/src/app/(auth)/login/page.tsx +49 -0
  46. package/template/base/src/app/(auth)/login/user-auth-form.tsx +152 -0
  47. package/template/base/src/app/(marketing)/layout.tsx +42 -0
  48. package/template/base/src/app/(marketing)/page.tsx +96 -0
  49. package/template/base/src/app/api/auth/[...nextauth]/route.ts +7 -0
  50. package/template/base/src/app/api/upload/route.ts +45 -0
  51. package/template/base/src/app/favicon.ico +0 -0
  52. package/template/base/src/app/layout.tsx +32 -0
  53. package/template/base/src/components/app-nav-command.tsx +160 -0
  54. package/template/base/src/components/dark-mode-toggle.tsx +43 -0
  55. package/template/base/src/components/data-table/data-table-column-header.tsx +91 -0
  56. package/template/base/src/components/data-table/data-table-faceted-filter.tsx +149 -0
  57. package/template/base/src/components/data-table/data-table-loading.tsx +77 -0
  58. package/template/base/src/components/data-table/data-table-pagination.tsx +94 -0
  59. package/template/base/src/components/data-table/data-table-toolbar.tsx +78 -0
  60. package/template/base/src/components/data-table/data-table-types.ts +17 -0
  61. package/template/base/src/components/data-table/data-table-view-options.tsx +59 -0
  62. package/template/base/src/components/data-table/data-table.tsx +301 -0
  63. package/template/base/src/components/data-table/simple-data-table.tsx +109 -0
  64. package/template/base/src/components/empty-placeholder.tsx +78 -0
  65. package/template/base/src/components/heading.tsx +17 -0
  66. package/template/base/src/components/icons.tsx +83 -0
  67. package/template/base/src/components/main-nav.tsx +64 -0
  68. package/template/base/src/components/mobile-nav.tsx +50 -0
  69. package/template/base/src/components/shell.tsx +13 -0
  70. package/template/base/src/components/side-nav.tsx +51 -0
  71. package/template/base/src/components/site-footer.tsx +31 -0
  72. package/template/base/src/components/system-info.tsx +36 -0
  73. package/template/base/src/components/theme-provider.tsx +13 -0
  74. package/template/base/src/components/ui/alert-dialog.tsx +145 -0
  75. package/template/base/src/components/ui/avatar.tsx +50 -0
  76. package/template/base/src/components/ui/badge.tsx +36 -0
  77. package/template/base/src/components/ui/button.tsx +56 -0
  78. package/template/base/src/components/ui/card.tsx +79 -0
  79. package/template/base/src/components/ui/checkbox.tsx +30 -0
  80. package/template/base/src/components/ui/command.tsx +155 -0
  81. package/template/base/src/components/ui/dialog.tsx +123 -0
  82. package/template/base/src/components/ui/dropdown-menu.tsx +200 -0
  83. package/template/base/src/components/ui/form.tsx +176 -0
  84. package/template/base/src/components/ui/input.tsx +25 -0
  85. package/template/base/src/components/ui/label.tsx +26 -0
  86. package/template/base/src/components/ui/popover.tsx +31 -0
  87. package/template/base/src/components/ui/select.tsx +121 -0
  88. package/template/base/src/components/ui/separator.tsx +31 -0
  89. package/template/base/src/components/ui/skeleton.tsx +15 -0
  90. package/template/base/src/components/ui/table.tsx +114 -0
  91. package/template/base/src/components/ui/textarea.tsx +24 -0
  92. package/template/base/src/components/ui/toast.tsx +127 -0
  93. package/template/base/src/components/ui/toaster.tsx +35 -0
  94. package/template/base/src/components/ui/use-toast.ts +189 -0
  95. package/template/base/src/components/user-account-nav.tsx +60 -0
  96. package/template/base/src/components/user-avatar.tsx +25 -0
  97. package/template/base/src/env.mjs +75 -0
  98. package/template/base/src/hooks/use-debounce.ts +17 -0
  99. package/template/base/src/hooks/use-lock-body.tsx +12 -0
  100. package/template/base/src/lib/auth.ts +79 -0
  101. package/template/base/src/lib/cn.ts +4 -0
  102. package/template/base/src/lib/db.ts +20 -0
  103. package/template/base/src/lib/delay.ts +2 -0
  104. package/template/base/src/lib/formatDate.ts +11 -0
  105. package/template/base/src/lib/generateLabel.ts +5 -0
  106. package/template/base/src/lib/siteConfig.ts +4 -0
  107. package/template/base/src/styles/editor.css +61 -0
  108. package/template/base/src/styles/globals.css +76 -0
  109. package/template/base/src/types/UnwrapPromise.ts +1 -0
  110. package/template/base/tailwind.config.ts +79 -0
  111. package/template/base/tsconfig.json +46 -0
  112. /package/template/{.eslintrc.cjs → advanced/.eslintrc.cjs} +0 -0
  113. /package/template/{next.config.mjs → advanced/next.config.mjs} +0 -0
  114. /package/template/{postcss.config.cjs → advanced/postcss.config.cjs} +0 -0
  115. /package/template/{prettier.config.ts → advanced/prettier.config.ts} +0 -0
  116. /package/template/{public → advanced/public}/next.svg +0 -0
  117. /package/template/{src → advanced/src}/app/(app)/dashboard/page.tsx +0 -0
  118. /package/template/{src → advanced/src}/app/(app)/layout.tsx +0 -0
  119. /package/template/{src → advanced/src}/app/(app)/roles/[id]/actions.ts +0 -0
  120. /package/template/{src → advanced/src}/app/(app)/roles/[id]/page.tsx +0 -0
  121. /package/template/{src → advanced/src}/app/(app)/roles/[id]/render.tsx +0 -0
  122. /package/template/{src → advanced/src}/app/(app)/roles/actions.ts +0 -0
  123. /package/template/{src → advanced/src}/app/(app)/roles/page.tsx +0 -0
  124. /package/template/{src → advanced/src}/app/(app)/roles/render.tsx +0 -0
  125. /package/template/{src → advanced/src}/app/(app)/settings/actions.ts +0 -0
  126. /package/template/{src → advanced/src}/app/(app)/settings/loading.tsx +0 -0
  127. /package/template/{src → advanced/src}/app/(app)/settings/page.tsx +0 -0
  128. /package/template/{src → advanced/src}/app/(app)/settings/render.tsx +0 -0
  129. /package/template/{src → advanced/src}/app/(app)/tasks/[id]/page.tsx +0 -0
  130. /package/template/{src → advanced/src}/app/(app)/users/[id]/actions.ts +0 -0
  131. /package/template/{src → advanced/src}/app/(app)/users/[id]/page.tsx +0 -0
  132. /package/template/{src → advanced/src}/app/(app)/users/[id]/render.tsx +0 -0
  133. /package/template/{src → advanced/src}/app/(app)/users/actions.ts +0 -0
  134. /package/template/{src → advanced/src}/app/(app)/users/page.tsx +0 -0
  135. /package/template/{src → advanced/src}/app/(app)/users/render.tsx +0 -0
  136. /package/template/{src → advanced/src}/app/(auth)/layout.tsx +0 -0
  137. /package/template/{src → advanced/src}/app/(auth)/login/page.tsx +0 -0
  138. /package/template/{src → advanced/src}/app/(auth)/login/user-auth-form.tsx +0 -0
  139. /package/template/{src → advanced/src}/app/(marketing)/layout.tsx +0 -0
  140. /package/template/{src → advanced/src}/app/(marketing)/page.tsx +0 -0
  141. /package/template/{src → advanced/src}/app/api/auth/[...nextauth]/route.ts +0 -0
  142. /package/template/{src → advanced/src}/app/favicon.ico +0 -0
  143. /package/template/{src → advanced/src}/components/app-nav-command.tsx +0 -0
  144. /package/template/{src → advanced/src}/components/dark-mode-toggle.tsx +0 -0
  145. /package/template/{src → advanced/src}/components/data-table/data-table-column-header.tsx +0 -0
  146. /package/template/{src → advanced/src}/components/data-table/data-table-faceted-filter.tsx +0 -0
  147. /package/template/{src → advanced/src}/components/data-table/data-table-loading.tsx +0 -0
  148. /package/template/{src → advanced/src}/components/data-table/data-table-pagination.tsx +0 -0
  149. /package/template/{src → advanced/src}/components/data-table/data-table-toolbar.tsx +0 -0
  150. /package/template/{src → advanced/src}/components/data-table/data-table-types.ts +0 -0
  151. /package/template/{src → advanced/src}/components/data-table/data-table-view-options.tsx +0 -0
  152. /package/template/{src → advanced/src}/components/data-table/data-table.tsx +0 -0
  153. /package/template/{src → advanced/src}/components/data-table/simple-data-table.tsx +0 -0
  154. /package/template/{src → advanced/src}/components/empty-placeholder.tsx +0 -0
  155. /package/template/{src → advanced/src}/components/heading.tsx +0 -0
  156. /package/template/{src → advanced/src}/components/icons.tsx +0 -0
  157. /package/template/{src → advanced/src}/components/main-nav.tsx +0 -0
  158. /package/template/{src → advanced/src}/components/mobile-nav.tsx +0 -0
  159. /package/template/{src → advanced/src}/components/shell.tsx +0 -0
  160. /package/template/{src → advanced/src}/components/side-nav.tsx +0 -0
  161. /package/template/{src → advanced/src}/components/site-footer.tsx +0 -0
  162. /package/template/{src → advanced/src}/components/system-info.tsx +0 -0
  163. /package/template/{src → advanced/src}/components/theme-provider.tsx +0 -0
  164. /package/template/{src → advanced/src}/components/ui/alert-dialog.tsx +0 -0
  165. /package/template/{src → advanced/src}/components/ui/avatar.tsx +0 -0
  166. /package/template/{src → advanced/src}/components/ui/badge.tsx +0 -0
  167. /package/template/{src → advanced/src}/components/ui/button.tsx +0 -0
  168. /package/template/{src → advanced/src}/components/ui/card.tsx +0 -0
  169. /package/template/{src → advanced/src}/components/ui/checkbox.tsx +0 -0
  170. /package/template/{src → advanced/src}/components/ui/command.tsx +0 -0
  171. /package/template/{src → advanced/src}/components/ui/dialog.tsx +0 -0
  172. /package/template/{src → advanced/src}/components/ui/dropdown-menu.tsx +0 -0
  173. /package/template/{src → advanced/src}/components/ui/form.tsx +0 -0
  174. /package/template/{src → advanced/src}/components/ui/input.tsx +0 -0
  175. /package/template/{src → advanced/src}/components/ui/label.tsx +0 -0
  176. /package/template/{src → advanced/src}/components/ui/popover.tsx +0 -0
  177. /package/template/{src → advanced/src}/components/ui/select.tsx +0 -0
  178. /package/template/{src → advanced/src}/components/ui/separator.tsx +0 -0
  179. /package/template/{src → advanced/src}/components/ui/skeleton.tsx +0 -0
  180. /package/template/{src → advanced/src}/components/ui/table.tsx +0 -0
  181. /package/template/{src → advanced/src}/components/ui/textarea.tsx +0 -0
  182. /package/template/{src → advanced/src}/components/ui/toast.tsx +0 -0
  183. /package/template/{src → advanced/src}/components/ui/toaster.tsx +0 -0
  184. /package/template/{src → advanced/src}/components/ui/use-toast.ts +0 -0
  185. /package/template/{src → advanced/src}/components/user-account-nav.tsx +0 -0
  186. /package/template/{src → advanced/src}/components/user-avatar.tsx +0 -0
  187. /package/template/{src → advanced/src}/hooks/use-debounce.ts +0 -0
  188. /package/template/{src → advanced/src}/hooks/use-lock-body.tsx +0 -0
  189. /package/template/{src → advanced/src}/lib/auth.ts +0 -0
  190. /package/template/{src → advanced/src}/lib/cn.ts +0 -0
  191. /package/template/{src → advanced/src}/lib/db.ts +0 -0
  192. /package/template/{src → advanced/src}/lib/delay.ts +0 -0
  193. /package/template/{src → advanced/src}/lib/formatDate.ts +0 -0
  194. /package/template/{src → advanced/src}/lib/generateLabel.ts +0 -0
  195. /package/template/{src → advanced/src}/lib/siteConfig.ts +0 -0
  196. /package/template/{src/app → advanced/src/styles}/globals.css +0 -0
  197. /package/template/{src → advanced/src}/types/UnwrapPromise.ts +0 -0
  198. /package/template/{tsconfig.json → advanced/tsconfig.json} +0 -0
@@ -0,0 +1,16 @@
1
+ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres?schema=public"
2
+ NEXTAUTH_SECRET="secret"
3
+ NEXTAUTH_URL="http://localhost:3000"
4
+ EMAIL_SERVER_HOST="example.com"
5
+ EMAIL_SERVER_PORT="123"
6
+ EMAIL_SERVER_USER="example@example.com"
7
+ EMAIL_SERVER_PASSWORD="password"
8
+ EMAIL_FROM="example@example.com"
9
+ GOOGLE_ID=""
10
+ GOOGLE_SECRET=""
11
+ GITHUB_ID=""
12
+ GITHUB_SECRET=""
13
+ FIREBASE_PROJECT_ID=""
14
+ FIREBASE_PRIVATE_KEY=""
15
+ FIREBASE_CLIENT_EMAIL=""
16
+ FIREBASE_STORAGE_BUCKET=""
@@ -0,0 +1,24 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2
+ const path = require('path')
3
+
4
+ /** @type {import("eslint").Linter.Config} */
5
+ const eslintConfig = {
6
+ overrides: [
7
+ {
8
+ extends: [],
9
+ files: ['*.ts', '*.tsx'],
10
+ parserOptions: {
11
+ project: path.join(__dirname, 'tsconfig.json')
12
+ }
13
+ }
14
+ ],
15
+ parser: '@typescript-eslint/parser',
16
+ parserOptions: {
17
+ project: path.join(__dirname, 'tsconfig.json')
18
+ },
19
+ plugins: ['@typescript-eslint'],
20
+ extends: ['next/core-web-vitals'],
21
+ rules: {}
22
+ }
23
+
24
+ module.exports = eslintConfig
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "default",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.cjs",
8
+ "css": "src/styles/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true
11
+ },
12
+ "aliases": {
13
+ "components": "@/components",
14
+ "utils": "@/lib/cn"
15
+ }
16
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
3
+ * for Docker builds.
4
+ */
5
+ await import('./src/env.mjs')
6
+
7
+ /** @type {import('next').NextConfig} */
8
+ const nextConfig = {
9
+ experimental: {
10
+ serverActions: true
11
+ },
12
+ i18n: {
13
+ locales: ['en'],
14
+ defaultLocale: 'en'
15
+ }
16
+ }
17
+
18
+ export default nextConfig
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "my-app",
3
+ "version": "1.0.0",
4
+ "description": "A Legendary Next.js App",
5
+ "private": true,
6
+ "scripts": {
7
+ "postinstall": "prisma generate",
8
+ "lint": "next lint",
9
+ "dev": "next dev",
10
+ "build": "next build",
11
+ "start": "next start",
12
+ "prisma:push": "prisma db push",
13
+ "prisma:gen": "prisma generate",
14
+ "prisma:studio": "prisma studio"
15
+ },
16
+ "dependencies": {
17
+ "@editorjs/checklist": "^1.5.0",
18
+ "@editorjs/delimiter": "^1.3.0",
19
+ "@editorjs/editorjs": "^2.28.0",
20
+ "@editorjs/header": "^2.7.0",
21
+ "@editorjs/image": "^2.8.1",
22
+ "@editorjs/list": "^1.8.0",
23
+ "@editorjs/quote": "^2.5.0",
24
+ "@editorjs/table": "^2.2.2",
25
+ "@ejekanshjain/cloud-storage": "^3.0.0",
26
+ "@hookform/resolvers": "^3.3.1",
27
+ "@next-auth/prisma-adapter": "^1.0.7",
28
+ "@prisma/client": "^5.3.1",
29
+ "@radix-ui/react-alert-dialog": "^1.0.4",
30
+ "@radix-ui/react-avatar": "^1.0.3",
31
+ "@radix-ui/react-checkbox": "^1.0.4",
32
+ "@radix-ui/react-dialog": "^1.0.4",
33
+ "@radix-ui/react-dropdown-menu": "^2.0.5",
34
+ "@radix-ui/react-label": "^2.0.2",
35
+ "@radix-ui/react-popover": "^1.0.6",
36
+ "@radix-ui/react-select": "^1.2.2",
37
+ "@radix-ui/react-separator": "^1.0.3",
38
+ "@radix-ui/react-slot": "^1.0.2",
39
+ "@radix-ui/react-toast": "^1.1.4",
40
+ "@t3-oss/env-nextjs": "^0.6.1",
41
+ "@tailwindcss/typography": "^0.5.10",
42
+ "@tanstack/react-table": "^8.10.1",
43
+ "@types/eslint": "^8.44.2",
44
+ "@types/lodash": "^4.14.199",
45
+ "@types/node": "^20.6.3",
46
+ "@types/nodemailer": "^6.4.10",
47
+ "@types/react": "^18.2.22",
48
+ "@types/react-dom": "^18.2.7",
49
+ "@typescript-eslint/eslint-plugin": "^6.7.2",
50
+ "@typescript-eslint/parser": "^6.7.2",
51
+ "@vercel/analytics": "^1.0.2",
52
+ "autoprefixer": "^10.4.16",
53
+ "class-variance-authority": "^0.7.0",
54
+ "clsx": "^2.0.0",
55
+ "cmdk": "^0.2.0",
56
+ "dayjs": "^1.11.10",
57
+ "editorjs-html": "^3.4.3",
58
+ "eslint": "^8.50.0",
59
+ "eslint-config-next": "^13.5.2",
60
+ "lodash": "^4.17.21",
61
+ "lucide-react": "^0.274.0",
62
+ "next": "^13.5.2",
63
+ "next-auth": "^4.23.1",
64
+ "next-themes": "^0.2.1",
65
+ "nodemailer": "^6.9.5",
66
+ "postcss": "^8.4.30",
67
+ "prettier": "^3.0.3",
68
+ "prettier-plugin-tailwindcss": "^0.5.4",
69
+ "prisma": "^5.3.1",
70
+ "react": "^18.2.0",
71
+ "react-dom": "^18.2.0",
72
+ "react-hook-form": "^7.46.2",
73
+ "tailwind-merge": "^1.14.0",
74
+ "tailwindcss": "^3.3.3",
75
+ "tailwindcss-animate": "^1.0.7",
76
+ "typescript": "^5.2.2",
77
+ "zod": "^3.22.2"
78
+ }
79
+ }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {}
5
+ }
6
+ }
@@ -0,0 +1,11 @@
1
+ import type { Config } from 'prettier'
2
+
3
+ const prettierConfig: Config = {
4
+ plugins: [require.resolve('prettier-plugin-tailwindcss')],
5
+ arrowParens: 'avoid',
6
+ trailingComma: 'none',
7
+ semi: false,
8
+ singleQuote: true
9
+ }
10
+
11
+ module.exports = prettierConfig
@@ -0,0 +1,115 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model Account {
11
+ id String @id @default(cuid())
12
+ userId String
13
+ type String
14
+ provider String
15
+ providerAccountId String
16
+ refresh_token String? @db.Text
17
+ access_token String? @db.Text
18
+ expires_at Int?
19
+ token_type String?
20
+ scope String?
21
+ id_token String? @db.Text
22
+ session_state String?
23
+
24
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
25
+
26
+ createdAt DateTime @default(now()) @db.Timestamptz()
27
+ updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
28
+
29
+ @@unique([provider, providerAccountId])
30
+ @@map("Accounts")
31
+ }
32
+
33
+ model Session {
34
+ id String @id @default(cuid())
35
+ sessionToken String @unique
36
+ userId String
37
+ expires DateTime @db.Timestamptz()
38
+
39
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
40
+
41
+ createdAt DateTime @default(now()) @db.Timestamptz()
42
+ updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
43
+
44
+ @@map("Sessions")
45
+ }
46
+
47
+ model User {
48
+ id String @id @default(cuid())
49
+ name String?
50
+ email String? @unique
51
+ emailVerified DateTime? @db.Timestamptz()
52
+ image String?
53
+ roleId String?
54
+
55
+ createdAt DateTime @default(now()) @db.Timestamptz()
56
+ updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
57
+
58
+ accounts Account[]
59
+ sessions Session[]
60
+
61
+ createdTasks Task[] @relation("createdTasks")
62
+ updatedTasks Task[] @relation("updatedTasks")
63
+
64
+ @@map("Users")
65
+ }
66
+
67
+ model VerificationToken {
68
+ identifier String
69
+ token String @unique
70
+ expires DateTime @db.Timestamptz()
71
+
72
+ @@unique([identifier, token])
73
+ @@map("VerificationTokens")
74
+ }
75
+
76
+ enum TaskStatus {
77
+ Backlog
78
+ Todo
79
+ In_Progress
80
+ Done
81
+ Cancelled
82
+ }
83
+
84
+ model Task {
85
+ id String @id @default(cuid())
86
+ title String
87
+ status TaskStatus
88
+ description Json?
89
+
90
+ images Resource[] @relation("taskImages")
91
+
92
+ createdAt DateTime @default(now()) @db.Timestamptz()
93
+ updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
94
+ createdById String
95
+ createdBy User @relation("createdTasks", fields: [createdById], references: [id], onDelete: Cascade)
96
+ updatedById String
97
+ updatedBy User @relation("updatedTasks", fields: [updatedById], references: [id], onDelete: Cascade)
98
+
99
+ @@map("Tasks")
100
+ }
101
+
102
+ model Resource {
103
+ id String @id @default(cuid())
104
+ originalFilename String
105
+ newFilename String @unique
106
+ url String @unique
107
+
108
+ taskId String?
109
+ task Task? @relation("taskImages", fields: [taskId], references: [id])
110
+
111
+ createdAt DateTime @default(now()) @db.Timestamptz()
112
+ updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz()
113
+
114
+ @@map("Resources")
115
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1,19 @@
1
+ import { Metadata } from 'next'
2
+
3
+ import { Heading } from '@/components/heading'
4
+ import { Shell } from '@/components/shell'
5
+ import { siteConfig } from '@/lib/siteConfig'
6
+
7
+ export const metadata: Metadata = {
8
+ title: 'Dashboard' + ' | ' + siteConfig.name
9
+ }
10
+
11
+ const DashboardPage = () => {
12
+ return (
13
+ <Shell>
14
+ <Heading heading="Dashboard" />
15
+ </Shell>
16
+ )
17
+ }
18
+
19
+ export default DashboardPage
@@ -0,0 +1,90 @@
1
+ import { notFound } from 'next/navigation'
2
+ import { ReactNode } from 'react'
3
+
4
+ import { AppNavCommand } from '@/components/app-nav-command'
5
+ import { MainNav } from '@/components/main-nav'
6
+ import { SideNav } from '@/components/side-nav'
7
+ import { SiteFooter } from '@/components/site-footer'
8
+ import { UserAccountNav } from '@/components/user-account-nav'
9
+ import { getAuthSession } from '@/lib/auth'
10
+
11
+ const Layout = async ({ children }: { children: ReactNode }) => {
12
+ const session = await getAuthSession()
13
+
14
+ if (!session?.user) return notFound()
15
+
16
+ return (
17
+ <div className="flex min-h-screen flex-col space-y-6">
18
+ <header className="sticky top-0 z-40 border-b bg-background">
19
+ <div className="container flex h-16 items-center justify-between py-4">
20
+ <MainNav
21
+ logoLink="/dashboard"
22
+ items={[
23
+ {
24
+ title: 'Dashboard',
25
+ href: '/dashboard'
26
+ },
27
+ {
28
+ title: 'Users',
29
+ href: '/users'
30
+ },
31
+ {
32
+ title: 'Tasks',
33
+ href: '/tasks'
34
+ }
35
+ ]}
36
+ />
37
+ <div className="flex items-center justify-center space-x-4">
38
+ <AppNavCommand
39
+ modules={{
40
+ task: true
41
+ }}
42
+ />
43
+ <UserAccountNav
44
+ user={{
45
+ name: session.user.name,
46
+ image: session.user.image,
47
+ email: session.user.email
48
+ }}
49
+ />
50
+ </div>
51
+ </div>
52
+ </header>
53
+ <div className="container grid flex-1 gap-12 md:grid-cols-[200px_1fr]">
54
+ <aside className="hidden w-[200px] flex-col md:flex">
55
+ <SideNav
56
+ items={[
57
+ {
58
+ title: 'Dashboard',
59
+ href: '/dashboard',
60
+ icon: 'dashboard'
61
+ },
62
+
63
+ {
64
+ title: 'Users',
65
+ href: '/users',
66
+ icon: 'user'
67
+ },
68
+ {
69
+ title: 'Tasks',
70
+ href: '/tasks',
71
+ icon: 'task'
72
+ },
73
+ {
74
+ title: 'Settings',
75
+ href: '/settings',
76
+ icon: 'settings'
77
+ }
78
+ ]}
79
+ />
80
+ </aside>
81
+ <main className="flex w-full flex-1 flex-col overflow-hidden">
82
+ {children}
83
+ </main>
84
+ </div>
85
+ <SiteFooter className="border-t" />
86
+ </div>
87
+ )
88
+ }
89
+
90
+ export default Layout
@@ -0,0 +1,18 @@
1
+ 'use server'
2
+
3
+ import { getAuthSession } from '@/lib/auth'
4
+ import { prisma } from '@/lib/db'
5
+
6
+ export const updateName = async ({ name }: { name: string }) => {
7
+ const session = await getAuthSession()
8
+ if (!session?.user) throw new Error('Unauthorized')
9
+
10
+ await prisma.user.update({
11
+ where: {
12
+ id: session.user.id
13
+ },
14
+ data: {
15
+ name
16
+ }
17
+ })
18
+ }
@@ -0,0 +1,28 @@
1
+ import { Heading } from '@/components/heading'
2
+ import { Shell } from '@/components/shell'
3
+ import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card'
4
+ import { Skeleton } from '@/components/ui/skeleton'
5
+
6
+ const Loading = () => {
7
+ return (
8
+ <Shell>
9
+ <Heading heading="Settings" text="Manage account and profile settings." />
10
+ <div className="grid gap-10">
11
+ <Card>
12
+ <CardHeader className="gap-2">
13
+ <Skeleton className="h-6 w-1/5" />
14
+ <Skeleton className="h-4 w-4/5" />
15
+ </CardHeader>
16
+ <CardContent className="h-10">
17
+ <Skeleton className="h-8 w-full max-w-[400px]" />
18
+ </CardContent>
19
+ <CardFooter>
20
+ <Skeleton className="h-8 w-full max-w-[120px]" />
21
+ </CardFooter>
22
+ </Card>
23
+ </div>
24
+ </Shell>
25
+ )
26
+ }
27
+
28
+ export default Loading
@@ -0,0 +1,28 @@
1
+ import { Metadata } from 'next'
2
+
3
+ import { Heading } from '@/components/heading'
4
+ import { Shell } from '@/components/shell'
5
+ import { getAuthSession } from '@/lib/auth'
6
+ import { siteConfig } from '@/lib/siteConfig'
7
+ import { Render } from './render'
8
+
9
+ export const metadata: Metadata = {
10
+ title: 'Settings' + ' | ' + siteConfig.name
11
+ }
12
+
13
+ const SettingsPage = async () => {
14
+ const session = await getAuthSession()
15
+
16
+ if (!session?.user) return
17
+
18
+ return (
19
+ <Shell>
20
+ <Heading heading="Settings" text="Manage account and profile settings." />
21
+ <div className="grid gap-10">
22
+ <Render name={session.user.name || ''} />
23
+ </div>
24
+ </Shell>
25
+ )
26
+ }
27
+
28
+ export default SettingsPage
@@ -0,0 +1,113 @@
1
+ 'use client'
2
+
3
+ import { zodResolver } from '@hookform/resolvers/zod'
4
+ import { useRouter } from 'next/navigation'
5
+ import { FC, useState } from 'react'
6
+ import { useForm } from 'react-hook-form'
7
+ import { z } from 'zod'
8
+
9
+ import { Icons } from '@/components/icons'
10
+ import { Button } from '@/components/ui/button'
11
+ import {
12
+ Card,
13
+ CardContent,
14
+ CardDescription,
15
+ CardFooter,
16
+ CardHeader,
17
+ CardTitle
18
+ } from '@/components/ui/card'
19
+ import {
20
+ Form,
21
+ FormControl,
22
+ FormField,
23
+ FormItem,
24
+ FormMessage
25
+ } from '@/components/ui/form'
26
+ import { Input } from '@/components/ui/input'
27
+ import { toast } from '@/components/ui/use-toast'
28
+ import { updateName } from './actions'
29
+
30
+ const userSchema = z.object({
31
+ name: z.string().nonempty()
32
+ })
33
+
34
+ type FormData = z.infer<typeof userSchema>
35
+
36
+ export const Render: FC<{ name: string }> = ({ name }) => {
37
+ const form = useForm<FormData>({
38
+ resolver: zodResolver(userSchema),
39
+ defaultValues: {
40
+ name
41
+ }
42
+ })
43
+ const router = useRouter()
44
+ const [isSaving, setIsSaving] = useState(false)
45
+
46
+ async function onSubmit(data: FormData) {
47
+ setIsSaving(true)
48
+
49
+ try {
50
+ await updateName({
51
+ ...data
52
+ })
53
+ toast({
54
+ title: 'Your name has been updated.'
55
+ })
56
+ router.refresh()
57
+ } catch (err) {
58
+ toast({
59
+ title: 'Internal Server Error',
60
+ variant: 'destructive',
61
+ description: 'Please try again later.'
62
+ })
63
+ }
64
+
65
+ setIsSaving(false)
66
+ }
67
+
68
+ return (
69
+ <Form {...form}>
70
+ <form onSubmit={form.handleSubmit(onSubmit)}>
71
+ <Card>
72
+ <CardHeader>
73
+ <CardTitle>Your Name</CardTitle>
74
+ <CardDescription>
75
+ Please enter your full name or a display name you are comfortable
76
+ with.
77
+ </CardDescription>
78
+ </CardHeader>
79
+ <CardContent>
80
+ <FormField
81
+ control={form.control}
82
+ name="name"
83
+ render={({ field }) => (
84
+ <FormItem className="max-w-[400px]">
85
+ <FormControl>
86
+ <Input
87
+ type="text"
88
+ placeholder="Your Name"
89
+ autoComplete="name"
90
+ disabled={isSaving}
91
+ {...field}
92
+ />
93
+ </FormControl>
94
+ <FormMessage />
95
+ </FormItem>
96
+ )}
97
+ />
98
+ </CardContent>
99
+ <CardFooter>
100
+ <Button type="submit" disabled={isSaving}>
101
+ {isSaving ? (
102
+ <Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
103
+ ) : (
104
+ <Icons.save className="mr-2 h-4 w-4" />
105
+ )}
106
+ <span>Save</span>
107
+ </Button>
108
+ </CardFooter>
109
+ </Card>
110
+ </form>
111
+ </Form>
112
+ )
113
+ }