create-zhx-monorepo 2.0.0 → 2.1.1

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 (62) hide show
  1. package/package.json +1 -1
  2. package/templates/monorepo-starter/apps/dashboard/next-env.d.ts +1 -1
  3. package/templates/monorepo-starter/apps/dashboard/src/components/forms/AuthForm.tsx +18 -24
  4. package/templates/monorepo-starter/apps/dashboard/src/components/layout/Header.tsx +1 -1
  5. package/templates/monorepo-starter/apps/dashboard/src/components/shared/VerifyAuthPage.tsx +1 -1
  6. package/templates/monorepo-starter/apps/dashboard/src/components/user/UserAccountSection.tsx +24 -32
  7. package/templates/monorepo-starter/gitignore +4 -3
  8. package/templates/monorepo-starter/packages/contracts/package.json +12 -0
  9. package/templates/monorepo-starter/packages/contracts/src/business/dto.ts +4 -0
  10. package/templates/monorepo-starter/packages/contracts/src/business/index.ts +2 -0
  11. package/templates/monorepo-starter/packages/contracts/src/business/schema.ts +32 -0
  12. package/templates/monorepo-starter/packages/contracts/src/business/types.d.ts +14 -0
  13. package/templates/monorepo-starter/packages/contracts/src/contact/dto.ts +18 -0
  14. package/templates/monorepo-starter/packages/contracts/src/contact/index.ts +2 -0
  15. package/templates/monorepo-starter/packages/contracts/src/contact/schema.ts +36 -0
  16. package/templates/monorepo-starter/packages/contracts/src/contact/types.d.ts +28 -0
  17. package/templates/monorepo-starter/packages/contracts/src/index.ts +2 -0
  18. package/templates/monorepo-starter/packages/contracts/src/lib/enums.ts +37 -0
  19. package/templates/monorepo-starter/packages/contracts/src/lib/prisma.ts +0 -1
  20. package/templates/monorepo-starter/packages/contracts/src/lib/types.d.ts +2 -2
  21. package/templates/monorepo-starter/packages/contracts/src/newsletter/dto.ts +18 -0
  22. package/templates/monorepo-starter/packages/contracts/src/newsletter/index.ts +2 -0
  23. package/templates/monorepo-starter/packages/contracts/src/newsletter/schema.ts +23 -0
  24. package/templates/monorepo-starter/packages/contracts/src/newsletter/types.d.ts +34 -0
  25. package/templates/monorepo-starter/packages/contracts/src/notification/schema.ts +1 -1
  26. package/templates/monorepo-starter/packages/contracts/tsup.config.ts +4 -1
  27. package/templates/monorepo-starter/packages/templates/src/email/components/actionBlock.tsx +1 -1
  28. package/templates/monorepo-starter/packages/templates/src/email/contactMessage.tsx +55 -0
  29. package/templates/monorepo-starter/packages/templates/src/email/index.ts +11 -2
  30. package/templates/monorepo-starter/packages/templates/src/email/newsletter.tsx +43 -0
  31. package/templates/monorepo-starter/packages/templates/src/email/securityAlert.tsx +8 -0
  32. package/templates/monorepo-starter/packages/templates/src/email/{auth/signin.tsx → signIn.tsx} +20 -19
  33. package/templates/monorepo-starter/packages/templates/src/email/{auth/signup.tsx → signUp.tsx} +24 -24
  34. package/templates/monorepo-starter/packages/templates/src/email/updateIdentifier.tsx +72 -0
  35. package/templates/monorepo-starter/packages/templates/src/email/updateMfa.tsx +88 -0
  36. package/templates/monorepo-starter/packages/templates/src/email/updatePassword.tsx +79 -0
  37. package/templates/monorepo-starter/packages/templates/src/email/userStatus.tsx +62 -0
  38. package/templates/monorepo-starter/packages/templates/src/email/{auth/verifyIdentifier.tsx → verifyIdentifier.tsx} +42 -42
  39. package/templates/monorepo-starter/packages/templates/src/email/verifyMfa.tsx +25 -0
  40. package/templates/monorepo-starter/packages/templates/src/lib/constants.ts +13 -16
  41. package/templates/monorepo-starter/packages/templates/src/lib/utils.ts +7 -8
  42. package/templates/monorepo-starter/packages/templates/src/types/global.d.ts +59 -19
  43. package/templates/monorepo-starter/server/prisma/schema.prisma +163 -21
  44. package/templates/monorepo-starter/server/src/lib/constants/index.ts +21 -16
  45. package/templates/monorepo-starter/server/src/modules/auth/auth.service.ts +68 -61
  46. package/templates/monorepo-starter/server/src/modules/auth/oauth.service.ts +6 -6
  47. package/templates/monorepo-starter/server/src/modules/auth/otp.service.ts +141 -16
  48. package/templates/monorepo-starter/server/src/modules/notification/notification.service.ts +28 -28
  49. package/templates/monorepo-starter/packages/contracts/src/lib/index.ts +0 -4
  50. package/templates/monorepo-starter/packages/templates/src/email/auth/disableMfa.tsx +0 -40
  51. package/templates/monorepo-starter/packages/templates/src/email/auth/index.ts +0 -10
  52. package/templates/monorepo-starter/packages/templates/src/email/auth/resetPassword.tsx +0 -41
  53. package/templates/monorepo-starter/packages/templates/src/email/auth/securityAlert.tsx +0 -21
  54. package/templates/monorepo-starter/packages/templates/src/email/auth/setPassword.tsx +0 -42
  55. package/templates/monorepo-starter/packages/templates/src/email/auth/updateIdentifier.tsx +0 -79
  56. package/templates/monorepo-starter/packages/templates/src/email/auth/updateMfa.tsx +0 -40
  57. package/templates/monorepo-starter/packages/templates/src/email/auth/verifyMfa.tsx +0 -23
  58. package/templates/monorepo-starter/packages/templates/src/email/service/accountReactivated.tsx +0 -31
  59. package/templates/monorepo-starter/packages/templates/src/email/service/accountSuspended.tsx +0 -37
  60. package/templates/monorepo-starter/packages/templates/src/email/service/index.ts +0 -2
  61. package/templates/monorepo-starter/packages/templates/src/email/test.tsx +0 -141
  62. /package/templates/monorepo-starter/{apps/dashboard/src/components/shared/ThemeSwitch.tsx → packages/ui/src/components/theme-toggle.tsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zhx-monorepo",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Create a ZHX monorepo with one command",
5
5
  "bin": {
6
6
  "create-zhx-monorepo": "bin/index.js"
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
3
+ import "./.next/dev/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -1,14 +1,16 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  "use client";
3
- import z from "zod";
4
- import Link from "next/link";
5
- import Image from "next/image";
6
- import { toast } from "sonner";
7
- import { useRouter } from "next/navigation";
8
- import { useEffect, useState } from "react";
3
+ import { cn } from "@workspace/ui/lib/utils";
4
+ import { Button } from "@workspace/ui/components/button";
5
+ import { Card, CardContent } from "@workspace/ui/components/card";
6
+ import { FieldDescription } from "@workspace/ui/components/field";
9
7
  import { useForm, useStore } from "@tanstack/react-form";
8
+ import { toast } from "sonner";
9
+ import { Form } from "@workspace/ui/components/form";
10
+ import Link from "next/link";
10
11
  import { GalleryVerticalEnd, LoaderCircle } from "lucide-react";
11
-
12
+ import OtpModal, { type OtpMeta } from "@workspace/ui/components/otp-modal";
13
+ import { useEffect, useState } from "react";
12
14
  import {
13
15
  requestOtp,
14
16
  resetPassword,
@@ -16,22 +18,16 @@ import {
16
18
  signUp,
17
19
  validateOtp,
18
20
  } from "@workspace/sdk/auth";
19
-
21
+ import SocialAuthField from "./SocialAuthField";
22
+ import { useRouter } from "next/navigation";
23
+ import { InputField } from "@workspace/ui/components/input-field";
24
+ import z from "zod";
20
25
  import {
21
26
  nameSchema,
22
27
  passwordSchema,
23
28
  identifierSchema,
24
29
  } from "@workspace/contracts";
25
-
26
- import { cn } from "@workspace/ui/lib/utils";
27
- import { Form } from "@workspace/ui/components/form";
28
- import { Button } from "@workspace/ui/components/button";
29
- import { Card, CardContent } from "@workspace/ui/components/card";
30
- import { FieldDescription } from "@workspace/ui/components/field";
31
- import { InputField } from "@workspace/ui/components/input-field";
32
- import OtpModal, { type OtpMeta } from "@workspace/ui/components/otp-modal";
33
-
34
- import SocialAuthField from "./SocialAuthField";
30
+ import Image from "next/image";
35
31
 
36
32
  interface AuthFormProps {
37
33
  formType: AuthFormType;
@@ -79,7 +75,7 @@ function AuthForm({ className, formType, queryParams }: AuthFormProps) {
79
75
  try {
80
76
  let message = `${formType} successfully!`;
81
77
  if (formType === "sign-up") {
82
- setOtpPurpose("authVerifyIdentifier");
78
+ setOtpPurpose("verifyIdentifier");
83
79
  const res = await signUp(value);
84
80
  message = res.message;
85
81
  setRedirectUrl("/auth/sign-in");
@@ -89,15 +85,13 @@ function AuthForm({ className, formType, queryParams }: AuthFormProps) {
89
85
  message = res.message;
90
86
  setRedirectUrl("/dashboard");
91
87
  if (res.action === "verifyMfa") {
92
- setOtpPurpose("authVerifyMfa");
88
+ setOtpPurpose("verifyMfa");
93
89
  setIsOpen(true);
94
90
  }
95
91
  } else if (formType.includes("password")) {
96
92
  if (!otpMeta?.token) {
97
93
  const nextPurpose: OtpPurpose =
98
- formType === "set-password"
99
- ? "authSetPassword"
100
- : "authResetPassword";
94
+ formType === "set-password" ? "setPassword" : "resetPassword";
101
95
  setOtpPurpose(nextPurpose);
102
96
  const res = await requestOtp({ identifier, purpose: nextPurpose });
103
97
  message = res.message;
@@ -117,7 +111,7 @@ function AuthForm({ className, formType, queryParams }: AuthFormProps) {
117
111
  } catch (err: any) {
118
112
  console.log("err ......", err);
119
113
  if (err.action === "verifyIdentifier") {
120
- setOtpPurpose("authVerifyIdentifier");
114
+ setOtpPurpose("verifyIdentifier");
121
115
  setRedirectUrl("/auth/sign-in");
122
116
  setIsOpen(true);
123
117
  }
@@ -1,6 +1,6 @@
1
1
  import { Separator } from "@workspace/ui/components/separator";
2
2
  import { SidebarTrigger } from "@workspace/ui/components/sidebar";
3
- import ThemeSwitch from "@/components/shared/ThemeSwitch";
3
+ import ThemeSwitch from "@workspace/ui/components/theme-toggle";
4
4
 
5
5
  const Header = () => {
6
6
  return (
@@ -41,7 +41,7 @@ function VerifyAuthPage({
41
41
  const verify = async () => {
42
42
  try {
43
43
  const isUpdateIdentifier =
44
- purpose === "authUpdateIdentifier" && newIdentifier;
44
+ purpose === "updateIdentifier" && newIdentifier;
45
45
 
46
46
  const res = isUpdateIdentifier
47
47
  ? await verifyUpdateIdentifier({
@@ -1,41 +1,33 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  "use client";
3
3
 
4
- import z from "zod";
4
+ import { useForm } from "@tanstack/react-form";
5
5
  import { toast } from "sonner";
6
6
  import { useEffect, useState } from "react";
7
- import { useForm } from "@tanstack/react-form";
8
7
  import { Mail, Shield, Phone, Smartphone, Loader2 } from "lucide-react";
9
-
10
- import {
11
- identifierSchema,
12
- passwordSchema,
13
- MfaMethodEnum,
14
- } from "@workspace/contracts";
15
-
8
+ import z from "zod";
9
+ import { identifierSchema, passwordSchema } from "@workspace/contracts";
16
10
  import {
17
11
  requestOtp,
18
12
  resetPassword,
19
13
  requestUpdateIdentifier,
20
14
  updateMfa,
21
15
  } from "@workspace/sdk/auth";
22
-
16
+ import { Form } from "@workspace/ui/components/form";
23
17
  import {
24
18
  Card,
25
19
  CardContent,
26
20
  CardHeader,
27
21
  CardTitle,
28
22
  } from "@workspace/ui/components/card";
29
- import { Form } from "@workspace/ui/components/form";
30
-
31
23
  import { Button } from "@workspace/ui/components/button";
32
- import { Badge } from "@workspace/ui/components/badge";
33
24
  import { InputField } from "@workspace/ui/components/input-field";
34
- import { SelectField } from "@workspace/ui/components/select-field";
35
25
  import OtpModal, { type OtpMeta } from "@workspace/ui/components/otp-modal";
36
-
37
- import UserSessions from "./UserSessions";
26
+ import { SelectField } from "@workspace/ui/components/select-field";
27
+ import { MfaMethodEnum } from "@workspace/contracts";
28
+ import { Badge } from "@workspace/ui/components/badge";
38
29
  import useUser from "@/hooks/user";
30
+ import UserSessions from "./UserSessions";
39
31
 
40
32
  type IdentifierType = "email" | "phone";
41
33
 
@@ -56,7 +48,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
56
48
 
57
49
  const schema = z.object({
58
50
  newIdentifier:
59
- otpPurpose === "authUpdateIdentifier"
51
+ otpPurpose === "updateIdentifier"
60
52
  ? identifierSchema
61
53
  : z.string().optional(),
62
54
  newPassword: otpPurpose?.includes("Password")
@@ -66,12 +58,12 @@ const AccountSection = ({ user }: AccountSectionProps) => {
66
58
  ? passwordSchema
67
59
  : z.string().optional(),
68
60
  preferredMfa:
69
- otpPurpose === "authUpdateMfa" ? MfaMethodEnum : MfaMethodEnum.optional(),
61
+ otpPurpose === "updateMfa" ? MfaMethodEnum : MfaMethodEnum.optional(),
70
62
  });
71
63
 
72
64
  const form = useForm({
73
65
  defaultValues: {
74
- newIdentifier: otpPurpose === "authUpdateIdentifier" ? "" : undefined,
66
+ newIdentifier: otpPurpose === "updateIdentifier" ? "" : undefined,
75
67
  newPassword: otpPurpose?.includes("Password") ? "" : undefined,
76
68
  confirmPassword: otpPurpose?.includes("Password") ? "" : undefined,
77
69
  preferredMfa: user.preferredMfa ?? "email",
@@ -85,7 +77,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
85
77
  setIsLoading(true);
86
78
  if (!otpMeta?.token) throw new Error("OTP token is missing");
87
79
 
88
- if (otpPurpose === "authUpdateIdentifier") {
80
+ if (otpPurpose === "updateIdentifier") {
89
81
  const res = await requestUpdateIdentifier({
90
82
  identifier: primaryIdentifier!,
91
83
  newIdentifier: value.newIdentifier!,
@@ -94,7 +86,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
94
86
  });
95
87
 
96
88
  message = res.message;
97
- } else if (otpPurpose === "authResetPassword") {
89
+ } else if (otpPurpose === "updatePassword") {
98
90
  const res = await resetPassword({
99
91
  identifier: primaryIdentifier!,
100
92
  purpose: otpPurpose,
@@ -103,7 +95,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
103
95
  });
104
96
 
105
97
  message = res.message;
106
- } else if (otpPurpose === "authUpdateMfa") {
98
+ } else if (otpPurpose === "updateMfa") {
107
99
  const res = await updateMfa({
108
100
  identifier: primaryIdentifier!,
109
101
  purpose: otpPurpose,
@@ -208,7 +200,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
208
200
  <Button
209
201
  variant="secondary"
210
202
  size="sm"
211
- onClick={() => handleOpen("authUpdateIdentifier", "email")}
203
+ onClick={() => handleOpen("updateIdentifier", "email")}
212
204
  disabled={isLoading}
213
205
  >
214
206
  {user.email ? "Change Email" : "Add Email"}
@@ -216,7 +208,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
216
208
  </div>
217
209
 
218
210
  {otpMeta?.valid &&
219
- otpPurpose === "authUpdateIdentifier" &&
211
+ otpPurpose === "updateIdentifier" &&
220
212
  identifierType === "email" && (
221
213
  <div className="space-y-4 p-4 border rounded-lg bg-muted/50">
222
214
  <InputField
@@ -284,7 +276,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
284
276
  <Button
285
277
  variant="secondary"
286
278
  size="sm"
287
- onClick={() => handleOpen("authUpdateIdentifier", "phone")}
279
+ onClick={() => handleOpen("updateIdentifier", "phone")}
288
280
  disabled={isLoading}
289
281
  >
290
282
  {user.phone ? "Change Phone" : "Add Phone"}
@@ -292,7 +284,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
292
284
  </div>
293
285
 
294
286
  {otpMeta?.valid &&
295
- otpPurpose === "authUpdateIdentifier" &&
287
+ otpPurpose === "updateIdentifier" &&
296
288
  identifierType === "phone" && (
297
289
  <div className="space-y-4 p-4 border rounded-lg bg-muted/50">
298
290
  <InputField
@@ -384,7 +376,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
384
376
  <Button
385
377
  size="sm"
386
378
  variant="secondary"
387
- onClick={() => handleOpen("authUpdateMfa")}
379
+ onClick={() => handleOpen("updateMfa")}
388
380
  >
389
381
  Change Method
390
382
  </Button>
@@ -392,7 +384,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
392
384
  <Button
393
385
  size="sm"
394
386
  variant="destructive"
395
- onClick={() => handleOpen("authDisableMfa")}
387
+ onClick={() => handleOpen("disableMfa")}
396
388
  >
397
389
  Disable
398
390
  </Button>
@@ -401,7 +393,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
401
393
  <Button
402
394
  size="sm"
403
395
  variant="secondary"
404
- onClick={() => handleOpen("authUpdateMfa")}
396
+ onClick={() => handleOpen("enableMfa")}
405
397
  disabled={isLoading}
406
398
  >
407
399
  Enable MFA
@@ -410,7 +402,7 @@ const AccountSection = ({ user }: AccountSectionProps) => {
410
402
  </div>
411
403
  </div>
412
404
 
413
- {otpMeta?.valid && otpPurpose === "authUpdateMfa" && (
405
+ {otpMeta?.valid && otpPurpose === "updateMfa" && (
414
406
  <div className="space-y-4 p-4 border rounded-lg">
415
407
  <SelectField
416
408
  form={form}
@@ -454,14 +446,14 @@ const AccountSection = ({ user }: AccountSectionProps) => {
454
446
  <Button
455
447
  variant="secondary"
456
448
  size="sm"
457
- onClick={() => handleOpen("authResetPassword")}
449
+ onClick={() => handleOpen("updatePassword")}
458
450
  disabled={isLoading}
459
451
  >
460
452
  Change Password
461
453
  </Button>
462
454
  </div>
463
455
 
464
- {otpMeta?.valid && otpPurpose === "authResetPassword" && (
456
+ {otpMeta?.valid && otpPurpose === "updatePassword" && (
465
457
  <div className="space-y-4 p-4 border rounded-lg">
466
458
  <InputField
467
459
  form={form}
@@ -28,8 +28,8 @@ coverage
28
28
 
29
29
  # Build Outputs
30
30
 
31
- .next/
32
- out/
31
+ .next
32
+ out
33
33
  build
34
34
  dist
35
35
 
@@ -44,8 +44,9 @@ logs
44
44
  \*.pem
45
45
 
46
46
  # Prisma
47
+ **/prisma/generated/
48
+ **/prisma/migrations/
47
49
 
48
- \*\*/prisma/generated/
49
50
 
50
51
  # others
51
52
 
@@ -22,6 +22,18 @@
22
22
  "import": "./dist/admin.js",
23
23
  "types": "./dist/admin.d.ts"
24
24
  },
25
+ "./business": {
26
+ "import": "./dist/business.js",
27
+ "types": "./dist/business.d.ts"
28
+ },
29
+ "./contact": {
30
+ "import": "./dist/contact.js",
31
+ "types": "./dist/contact.d.ts"
32
+ },
33
+ "./newsletter": {
34
+ "import": "./dist/newsletter.js",
35
+ "types": "./dist/newsletter.d.ts"
36
+ },
25
37
  "./user": {
26
38
  "import": "./dist/user.js",
27
39
  "types": "./dist/user.d.ts"
@@ -0,0 +1,4 @@
1
+ import { createZodDto } from "nestjs-zod";
2
+ import { businessProfileSchema } from "./schema";
3
+
4
+ export class BusinessProfileDto extends createZodDto(businessProfileSchema) {}
@@ -0,0 +1,2 @@
1
+ export * from "./schema";
2
+ export * from "./dto";
@@ -0,0 +1,32 @@
1
+ import z from "zod";
2
+ import { emailSchema, phoneSchema, idSchema } from "../lib/schema";
3
+
4
+ export const businessProfileSchema = z.object({
5
+ name: z.string().min(1),
6
+ legalName: z.string(),
7
+ slug: z.string().min(1),
8
+ description: z.string(),
9
+
10
+ logoId: idSchema,
11
+ coverImageId: idSchema.optional(),
12
+
13
+ email: emailSchema,
14
+ phone: phoneSchema,
15
+ website: z.url(),
16
+
17
+ tiktok: z.url().optional(),
18
+ facebook: z.url().optional(),
19
+ instagram: z.url().optional(),
20
+ twitter: z.url().optional(),
21
+ linkedin: z.url().optional(),
22
+ youtube: z.url().optional(),
23
+
24
+ address: z.string(),
25
+ city: z.string(),
26
+ state: z.string(),
27
+ country: z.string(),
28
+ postalCode: z.string(),
29
+
30
+ metaTitle: z.string(),
31
+ metaDescription: z.string(),
32
+ });
@@ -0,0 +1,14 @@
1
+ import type z from "zod";
2
+ import type { businessProfileSchema } from "./schema";
3
+ import { type BusinessProfile } from "../lib/prisma";
4
+
5
+ declare global {
6
+ type BusinessProfileType = z.input<typeof businessProfileSchema>;
7
+ type BusinessProfileDto = z.output<typeof businessProfileSchema>;
8
+
9
+ interface BusinessProfileResponse extends Sanitize<BusinessProfile> {
10
+ logo?: MediaResponse;
11
+ }
12
+ }
13
+
14
+ export {};
@@ -0,0 +1,18 @@
1
+ import { createZodDto } from "nestjs-zod";
2
+ import {
3
+ createContactMessageSchema,
4
+ updateContactMessageSchema,
5
+ contactMessageQuerySchema,
6
+ } from "./schema";
7
+
8
+ export class CreateContactMessageDto extends createZodDto(
9
+ createContactMessageSchema,
10
+ ) {}
11
+
12
+ export class UpdateContactMessageDto extends createZodDto(
13
+ updateContactMessageSchema,
14
+ ) {}
15
+
16
+ export class ContactMessageQueryDto extends createZodDto(
17
+ contactMessageQuerySchema,
18
+ ) {}
@@ -0,0 +1,2 @@
1
+ export * from "./schema";
2
+ export * from "./dto";
@@ -0,0 +1,36 @@
1
+ import z from "zod";
2
+ import {
3
+ baseQuerySchema,
4
+ emailSchema,
5
+ isoDateSchema,
6
+ nameSchema,
7
+ phoneSchema,
8
+ } from "../lib/schema";
9
+ import {
10
+ ContactMessageSearchByEnum,
11
+ ContactMessageSortByEnum,
12
+ ContactMessageStatusEnum,
13
+ } from "../lib/enums";
14
+
15
+ export const createContactMessageSchema = z.object({
16
+ firstName: nameSchema,
17
+ lastName: nameSchema.optional(),
18
+ email: emailSchema,
19
+ phone: phoneSchema,
20
+ subject: z.string().optional(),
21
+ message: z.string(),
22
+ source: z.string().optional(),
23
+ });
24
+
25
+ export const updateContactMessageSchema = z.object({
26
+ replyNotes: z.string().optional(),
27
+ status: ContactMessageStatusEnum,
28
+ repliedAt: isoDateSchema,
29
+ });
30
+
31
+ export const contactMessageQuerySchema = baseQuerySchema(
32
+ ContactMessageSortByEnum,
33
+ ContactMessageSearchByEnum,
34
+ ).extend({
35
+ status: ContactMessageStatusEnum.optional(),
36
+ });
@@ -0,0 +1,28 @@
1
+ import type z from "zod";
2
+ import type {
3
+ createContactMessageSchema,
4
+ updateContactMessageSchema,
5
+ contactMessageQuerySchema,
6
+ } from "./schema";
7
+ import { type ContactMessage } from "../lib/prisma";
8
+
9
+ declare global {
10
+ type CreateContactMessageType = z.input<typeof createContactMessageSchema>;
11
+ type CreateContactMessageDto = z.output<typeof createContactMessageSchema>;
12
+
13
+ type UpdateContactMessageType = z.input<typeof updateContactMessageSchema>;
14
+ type UpdateContactMessageDto = z.output<typeof updateContactMessageSchema>;
15
+
16
+ type ContactMessageQueryType = z.input<typeof contactMessageQuerySchema>;
17
+ type ContactMessageQueryDto = z.output<typeof contactMessageQuerySchema>;
18
+
19
+ interface ContactMessageResponse extends Sanitize<ContactMessage> {
20
+ repliedBy?: BaseUserResponse;
21
+ }
22
+
23
+ interface ContactMessageQueryResponse extends BaseQueryResponse {
24
+ messages: ContactMessageResponse[];
25
+ }
26
+ }
27
+
28
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from "./lib/enums";
2
+ export * from "./lib/schema";
@@ -22,6 +22,8 @@ export const NotificationPurposeEnum = z.enum($Enums.NotificationPurpose);
22
22
  export const NotificationStatusEnum = z.enum($Enums.NotificationStatus);
23
23
  export const NotificationPriorityEnum = z.enum($Enums.NotificationPriority);
24
24
 
25
+ export const ContactMessageStatusEnum = z.enum($Enums.ContactMessageStatus);
26
+
25
27
  /* =========================
26
28
  SHARED - VARIABLES
27
29
  ========================= */
@@ -53,3 +55,38 @@ export const MediaVisibilityEnum = z.enum($Enums.MediaVisibility);
53
55
 
54
56
  export const MediaSearchByEnum = z.enum(["id", "title"]);
55
57
  export const MediaSortByEnum = z.enum(["size", "title", "type"]);
58
+
59
+ /* =========================
60
+ CONTACT MESSAGE
61
+ ========================= */
62
+ export const ContactMessageSortByEnum = z.enum([
63
+ "name",
64
+ "email",
65
+ "phone",
66
+ "subject",
67
+ "repliedAt",
68
+ ]);
69
+
70
+ export const ContactMessageSearchByEnum = z.enum([
71
+ "name",
72
+ "email",
73
+ "phone",
74
+ "subject",
75
+ "source",
76
+ ]);
77
+
78
+ /* =========================
79
+ NEWSLETTER SUBSCRIBER
80
+ ========================= */
81
+ export const NewsletterSubscriberSortByEnum = z.enum([
82
+ "name",
83
+ "email",
84
+ "subscribedAt",
85
+ "unsubscribedAt",
86
+ ]);
87
+
88
+ export const NewsletterSubscriberSearchByEnum = z.enum([
89
+ "name",
90
+ "email",
91
+ "source",
92
+ ]);
@@ -1,2 +1 @@
1
1
  export * from "../../../../server/prisma/generated/browser";
2
- export { Decimal } from "../../../../server/prisma/generated/internal/prismaNamespaceBrowser";
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import * as enums from "./enums";
3
3
  import React from "react";
4
- import { Decimal } from "../lib/prisma";
4
+ import { Prisma } from "../lib/prisma";
5
5
 
6
6
  /* ======================================================
7
7
  GLOBAL DECLARATIONS
@@ -13,7 +13,7 @@ declare global {
13
13
  -------------------- */
14
14
 
15
15
  type Nullable<T> = T | null;
16
- type DecimalInstance = InstanceType<typeof Decimal>;
16
+ type DecimalInstance = InstanceType<typeof Prisma.Decimal>;
17
17
  type StrictOmit<T, K extends keyof T> = Omit<T, K>;
18
18
  type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
19
19
  type ArrayItem<T> = T extends any[] ? T[number] : never;
@@ -0,0 +1,18 @@
1
+ import { createZodDto } from "nestjs-zod";
2
+ import {
3
+ newsletterSubscriberSchema,
4
+ newsletterUnSubscriberSchema,
5
+ newsletterSubscriberQuerySchema,
6
+ } from "./schema";
7
+
8
+ export class NewsletterSubscriberDto extends createZodDto(
9
+ newsletterSubscriberSchema,
10
+ ) {}
11
+
12
+ export class NewsletterUnSubscriberDto extends createZodDto(
13
+ newsletterUnSubscriberSchema,
14
+ ) {}
15
+
16
+ export class NewsletterSubscriberQueryDto extends createZodDto(
17
+ newsletterSubscriberQuerySchema,
18
+ ) {}
@@ -0,0 +1,2 @@
1
+ export * from "./schema";
2
+ export * from "./dto";
@@ -0,0 +1,23 @@
1
+ import z from "zod";
2
+ import {
3
+ NewsletterSubscriberSearchByEnum,
4
+ NewsletterSubscriberSortByEnum,
5
+ } from "../lib/enums";
6
+ import { nameSchema, emailSchema, baseQuerySchema } from "../lib/schema";
7
+
8
+ export const newsletterSubscriberSchema = z.object({
9
+ name: nameSchema,
10
+ email: emailSchema,
11
+ source: z.string(),
12
+ });
13
+
14
+ export const newsletterUnSubscriberSchema = z.object({
15
+ email: emailSchema,
16
+ });
17
+
18
+ export const newsletterSubscriberQuerySchema = baseQuerySchema(
19
+ NewsletterSubscriberSortByEnum,
20
+ NewsletterSubscriberSearchByEnum,
21
+ ).extend({
22
+ isActive: z.boolean().optional(),
23
+ });
@@ -0,0 +1,34 @@
1
+ import type z from "zod";
2
+ import type {
3
+ newsletterSubscriberSchema,
4
+ newsletterUnSubscriberSchema,
5
+ newsletterSubscriberQuerySchema,
6
+ } from "./schema";
7
+ import { type NewsletterSubscriber } from "../lib/prisma";
8
+
9
+ declare global {
10
+ type NewsletterSubscriberType = z.input<typeof newsletterSubscriberSchema>;
11
+ type NewsletterSubscriberDto = z.output<typeof newsletterSubscriberSchema>;
12
+
13
+ type NewsletterUnSubscriberType = z.input<
14
+ typeof newsletterUnSubscriberSchema
15
+ >;
16
+ type NewsletterUnSubscriberDto = z.output<
17
+ typeof newsletterUnSubscriberSchema
18
+ >;
19
+
20
+ type NewsletterSubscriberQueryType = z.input<
21
+ typeof newsletterSubscriberQuerySchema
22
+ >;
23
+ type NewsletterSubscriberQueryDto = z.output<
24
+ typeof newsletterSubscriberQuerySchema
25
+ >;
26
+
27
+ type NewsletterSubscriberResponse = Sanitize<NewsletterSubscriber>;
28
+
29
+ interface NewsletterSubscriberQueryResponse extends BaseQueryResponse {
30
+ users: NewsletterSubscriberResponse[];
31
+ }
32
+ }
33
+
34
+ export {};
@@ -1,5 +1,5 @@
1
1
  import z from "zod";
2
- import { PushProviderEnum } from "../lib";
2
+ import { PushProviderEnum } from "../lib/enums";
3
3
 
4
4
  export const registerPushTokenSchema = z.object({
5
5
  token: z.string().min(1),