@mac777/project-pinecone-schema 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events/events.constants.d.ts +1 -8
- package/dist/events/events.constants.js +1 -6
- package/dist/events/events.schema.d.ts +110 -55
- package/dist/events/events.type.d.ts +0 -8
- package/dist/events/utils/ticket.schema.d.ts +6 -3
- package/dist/events/utils/ticket.schema.js +2 -1
- package/package.json +2 -5
- package/src/auth/auth.constants.ts +9 -0
- package/src/auth/auth.schema.ts +65 -0
- package/src/auth/auth.type.ts +42 -0
- package/src/auth/index.ts +3 -0
- package/src/auth/utils/password.schema.ts +18 -0
- package/src/events/events.constants.ts +170 -0
- package/src/events/events.schema.ts +158 -0
- package/src/events/events.type.ts +51 -0
- package/src/events/events.utils.schema.ts +5 -0
- package/{dist/events/events.d.ts → src/events/index.ts} +4 -3
- package/src/events/utils/admin.schema.ts +77 -0
- package/src/events/utils/age.restriction.schema.ts +3 -0
- package/src/events/utils/document.schema.ts +8 -0
- package/src/events/utils/event.type.schema.ts +3 -0
- package/src/events/utils/media.schema.ts +36 -0
- package/src/events/utils/organizer.schema.ts +14 -0
- package/src/events/utils/schedule.schema.ts +10 -0
- package/src/events/utils/ticket.schema.ts +33 -0
- package/src/events/utils/venue.schema.ts +22 -0
- package/src/index.ts +5 -0
- package/src/media/index.ts +2 -0
- package/src/media/media.schema.ts +37 -0
- package/src/media/media.type.ts +18 -0
- package/src/media/utils/backblaze.schema.ts +8 -0
- package/src/media/utils/imagekit.schema.ts +20 -0
- package/src/orders/index.ts +6 -0
- package/src/orders/orders.schema.ts +106 -0
- package/src/orders/orders.type.ts +85 -0
- package/src/orders/payments.schema.ts +81 -0
- package/src/orders/payments.type.ts +87 -0
- package/src/orders/ticket.schema.ts +78 -0
- package/src/orders/ticket.type.ts +103 -0
- package/tsconfig.json +13 -0
- package/dist/auth.d.ts +0 -1
- package/dist/auth.js +0 -18
- package/dist/events/admin.schema.d.ts +0 -208
- package/dist/events/admin.schema.js +0 -70
- package/dist/events/age.restriction.schema.d.ts +0 -2
- package/dist/events/age.restriction.schema.js +0 -5
- package/dist/events/document.schema.d.ts +0 -17
- package/dist/events/document.schema.js +0 -10
- package/dist/events/event.schema.d.ts +0 -0
- package/dist/events/event.schema.js +0 -1
- package/dist/events/event.type.schema.d.ts +0 -2
- package/dist/events/event.type.schema.js +0 -5
- package/dist/events/events.constant.d.ts +0 -9
- package/dist/events/events.constant.js +0 -12
- package/dist/events/events.js +0 -19
- package/dist/events/media.schema.d.ts +0 -77
- package/dist/events/media.schema.js +0 -36
- package/dist/events/organizer.schema.d.ts +0 -55
- package/dist/events/organizer.schema.js +0 -15
- package/dist/events/schedule.schema.d.ts +0 -20
- package/dist/events/schedule.schema.js +0 -11
- package/dist/events/step.schema.d.ts +0 -0
- package/dist/events/step.schema.js +0 -1
- package/dist/events/ticket.schema.d.ts +0 -113
- package/dist/events/ticket.schema.js +0 -29
- package/dist/events/utils.schema.d.ts +0 -6
- package/dist/events/utils.schema.js +0 -22
- package/dist/events/venue.schema.d.ts +0 -75
- package/dist/events/venue.schema.js +0 -22
- package/dist/events.constant.d.ts +0 -9
- package/dist/events.constant.js +0 -12
- package/dist/events.constants.d.ts +0 -9
- package/dist/events.constants.js +0 -12
- package/dist/events.d.ts +0 -39
- package/dist/events.js +0 -2
- package/dist/events.schema.d.ts +0 -229
- package/dist/events.schema.js +0 -95
- package/dist/events.type.d.ts +0 -42
- package/dist/events.type.js +0 -2
- package/dist/events.utils.schema.d.ts +0 -6
- package/dist/events.utils.schema.js +0 -22
|
@@ -32,14 +32,6 @@ export type StepTicketsData = z.infer<typeof stepTicketsSchema>;
|
|
|
32
32
|
export type StepReviewData = z.infer<typeof stepReviewSchema>;
|
|
33
33
|
export type SubmitEventData = z.infer<typeof submitEventSchema>;
|
|
34
34
|
export type DraftEventData = z.infer<typeof draftEventSchema>;
|
|
35
|
-
export interface Event {
|
|
36
|
-
id: string;
|
|
37
|
-
title: string;
|
|
38
|
-
location: string;
|
|
39
|
-
category: string;
|
|
40
|
-
date: string;
|
|
41
|
-
image?: string;
|
|
42
|
-
}
|
|
43
35
|
export type GetEventData = z.infer<typeof getEventSchema>;
|
|
44
36
|
export type ProtectedEventData = z.infer<typeof protectedEventSchema>;
|
|
45
37
|
export type ClientGetEventData = z.infer<typeof clientGetEventSchema>;
|
|
@@ -30,7 +30,7 @@ export declare const limitsSchema: z.ZodObject<{
|
|
|
30
30
|
maxPerOrder?: number | undefined;
|
|
31
31
|
}>;
|
|
32
32
|
export declare const displayTicketSchema: z.ZodObject<{
|
|
33
|
-
|
|
33
|
+
_id: z.ZodOptional<z.ZodString>;
|
|
34
34
|
name: z.ZodString;
|
|
35
35
|
description: z.ZodOptional<z.ZodString>;
|
|
36
36
|
price: z.ZodObject<{
|
|
@@ -66,6 +66,7 @@ export declare const displayTicketSchema: z.ZodObject<{
|
|
|
66
66
|
}>>;
|
|
67
67
|
remaining: z.ZodOptional<z.ZodNumber>;
|
|
68
68
|
sold: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
reserved: z.ZodOptional<z.ZodNumber>;
|
|
69
70
|
visibility: z.ZodOptional<z.ZodDefault<z.ZodEnum<["public", "hidden", "invite_only"]>>>;
|
|
70
71
|
status: z.ZodOptional<z.ZodDefault<z.ZodEnum<["active", "inactive"]>>>;
|
|
71
72
|
benefits: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -79,7 +80,7 @@ export declare const displayTicketSchema: z.ZodObject<{
|
|
|
79
80
|
quantity: number;
|
|
80
81
|
tier: "early_bird" | "regular" | "vip";
|
|
81
82
|
status?: "active" | "inactive" | undefined;
|
|
82
|
-
|
|
83
|
+
_id?: string | undefined;
|
|
83
84
|
description?: string | undefined;
|
|
84
85
|
salesWindow?: {
|
|
85
86
|
startDate?: string | undefined;
|
|
@@ -91,6 +92,7 @@ export declare const displayTicketSchema: z.ZodObject<{
|
|
|
91
92
|
} | undefined;
|
|
92
93
|
remaining?: number | undefined;
|
|
93
94
|
sold?: number | undefined;
|
|
95
|
+
reserved?: number | undefined;
|
|
94
96
|
visibility?: "public" | "hidden" | "invite_only" | undefined;
|
|
95
97
|
benefits?: string[] | undefined;
|
|
96
98
|
}, {
|
|
@@ -101,7 +103,7 @@ export declare const displayTicketSchema: z.ZodObject<{
|
|
|
101
103
|
};
|
|
102
104
|
quantity: number;
|
|
103
105
|
status?: "active" | "inactive" | undefined;
|
|
104
|
-
|
|
106
|
+
_id?: string | undefined;
|
|
105
107
|
description?: string | undefined;
|
|
106
108
|
salesWindow?: {
|
|
107
109
|
startDate?: string | undefined;
|
|
@@ -113,6 +115,7 @@ export declare const displayTicketSchema: z.ZodObject<{
|
|
|
113
115
|
} | undefined;
|
|
114
116
|
remaining?: number | undefined;
|
|
115
117
|
sold?: number | undefined;
|
|
118
|
+
reserved?: number | undefined;
|
|
116
119
|
visibility?: "public" | "hidden" | "invite_only" | undefined;
|
|
117
120
|
benefits?: string[] | undefined;
|
|
118
121
|
tier?: "early_bird" | "regular" | "vip" | undefined;
|
|
@@ -15,7 +15,7 @@ exports.limitsSchema = zod_1.z.object({
|
|
|
15
15
|
maxPerOrder: zod_1.z.number({ required_error: 'Max per order must be a number' }).int('Max per order must be an integer').min(1, 'Max per order must be at least 1').default(10),
|
|
16
16
|
});
|
|
17
17
|
exports.displayTicketSchema = zod_1.z.object({
|
|
18
|
-
|
|
18
|
+
_id: zod_1.z.string().optional(),
|
|
19
19
|
name: zod_1.z.string({ required_error: 'Ticket name is required' }),
|
|
20
20
|
description: zod_1.z.string().optional(),
|
|
21
21
|
price: exports.priceSchema,
|
|
@@ -24,6 +24,7 @@ exports.displayTicketSchema = zod_1.z.object({
|
|
|
24
24
|
limits: exports.limitsSchema.optional(),
|
|
25
25
|
remaining: zod_1.z.number().optional(),
|
|
26
26
|
sold: zod_1.z.number().optional(),
|
|
27
|
+
reserved: zod_1.z.number().optional(),
|
|
27
28
|
visibility: zod_1.z.enum(['public', 'hidden', 'invite_only'], { required_error: 'Ticket visibility must be public, hidden, or invite_only' }).default('public').optional(),
|
|
28
29
|
status: zod_1.z.enum(['active', 'inactive'], { required_error: 'Ticket status must be active or inactive' }).default('active').optional(),
|
|
29
30
|
benefits: zod_1.z.array(zod_1.z.string(), { required_error: 'Benefits must be an array of strings' }).optional(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mac777/project-pinecone-schema",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -11,11 +11,8 @@
|
|
|
11
11
|
"zod": "^3.22.4",
|
|
12
12
|
"zxcvbn": "^4.4.2"
|
|
13
13
|
},
|
|
14
|
-
"files": ["dist"],
|
|
15
|
-
"publishConfig": {
|
|
16
|
-
"access": "public"
|
|
17
|
-
},
|
|
18
14
|
"devDependencies": {
|
|
15
|
+
"@types/zxcvbn": "^4.4.5",
|
|
19
16
|
"typescript": "^5.0.0"
|
|
20
17
|
}
|
|
21
18
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Password strength requirements
|
|
2
|
+
export const MIN_PASSWORD_LENGTH = 8;
|
|
3
|
+
export const MAX_PASSWORD_LENGTH = 128;
|
|
4
|
+
export const MIN_FIRST_NAME_LENGTH = 3;
|
|
5
|
+
export const MAX_FIRST_NAME_LENGTH = 20;
|
|
6
|
+
export const MIN_LAST_NAME_LENGTH = 3;
|
|
7
|
+
export const MAX_LAST_NAME_LENGTH = 20;
|
|
8
|
+
export const MIN_ORGANIZATION_NAME_LENGTH = 3;
|
|
9
|
+
export const MAX_ORGANIZATION_NAME_LENGTH = 20;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { passwordSchema, confirmPasswordSchema, strongPasswordSchema } from './utils/password.schema';
|
|
3
|
+
import {
|
|
4
|
+
MIN_FIRST_NAME_LENGTH,
|
|
5
|
+
MAX_FIRST_NAME_LENGTH,
|
|
6
|
+
MIN_LAST_NAME_LENGTH,
|
|
7
|
+
MAX_LAST_NAME_LENGTH,
|
|
8
|
+
MIN_ORGANIZATION_NAME_LENGTH,
|
|
9
|
+
MAX_ORGANIZATION_NAME_LENGTH
|
|
10
|
+
} from './auth.constants';
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// AUTH SCHEMAS
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
// Login schema
|
|
17
|
+
export const loginSchema = z.object({
|
|
18
|
+
email: z.string().email('Please enter a valid email address'),
|
|
19
|
+
password: z.string().min(1, 'Password is required'),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Base user schema
|
|
23
|
+
const baseUserSchema = z.object({
|
|
24
|
+
firstName: z.string()
|
|
25
|
+
.trim()
|
|
26
|
+
.min(MIN_FIRST_NAME_LENGTH, `First name must be at least ${MIN_FIRST_NAME_LENGTH} characters long`)
|
|
27
|
+
.max(MAX_FIRST_NAME_LENGTH, `First name must be at most ${MAX_FIRST_NAME_LENGTH} characters long`),
|
|
28
|
+
lastName: z.string()
|
|
29
|
+
.trim()
|
|
30
|
+
.min(MIN_LAST_NAME_LENGTH, `Last name must be at least ${MIN_LAST_NAME_LENGTH} characters long`)
|
|
31
|
+
.max(MAX_LAST_NAME_LENGTH, `Last name must be at most ${MAX_LAST_NAME_LENGTH} characters long`),
|
|
32
|
+
email: z.string().trim().email(),
|
|
33
|
+
password: strongPasswordSchema,
|
|
34
|
+
confirmPassword: confirmPasswordSchema,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Register schema for regular users
|
|
38
|
+
export const registerSchema = baseUserSchema.extend({
|
|
39
|
+
organizationName: z.string().optional(),
|
|
40
|
+
organizationType: z.enum(['Venue', 'Promoter', 'Festival Organizer']).optional(),
|
|
41
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
42
|
+
message: "Passwords don't match",
|
|
43
|
+
path: ["confirmPassword"],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Register schema for host users
|
|
47
|
+
export const registerHostSchema = baseUserSchema.extend({
|
|
48
|
+
organizationName: z.string()
|
|
49
|
+
.trim()
|
|
50
|
+
.min(MIN_ORGANIZATION_NAME_LENGTH, `Organization name must be at least ${MIN_ORGANIZATION_NAME_LENGTH} characters long`)
|
|
51
|
+
.max(MAX_ORGANIZATION_NAME_LENGTH, `Organization name must be at most ${MAX_ORGANIZATION_NAME_LENGTH} characters long`),
|
|
52
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
53
|
+
message: 'Passwords do not match',
|
|
54
|
+
path: ['confirmPassword'],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export const updateGoogleUserOrganizationSchema = z.object({
|
|
59
|
+
organization: z.string()
|
|
60
|
+
.trim()
|
|
61
|
+
.min(MIN_ORGANIZATION_NAME_LENGTH, `Organization name must be at least ${MIN_ORGANIZATION_NAME_LENGTH} characters long`)
|
|
62
|
+
.max(MAX_ORGANIZATION_NAME_LENGTH, `Organization name must be at most ${MAX_ORGANIZATION_NAME_LENGTH} characters long`),
|
|
63
|
+
id: z.string({ required_error: 'Unauthorized' }).regex(/^[0-9a-fA-F]{24}$/, 'Unauthorized'),
|
|
64
|
+
});
|
|
65
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loginSchema, registerSchema, registerHostSchema, updateGoogleUserOrganizationSchema } from './auth.schema';
|
|
3
|
+
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// TYPE EXPORTS
|
|
6
|
+
// =============================================================================
|
|
7
|
+
|
|
8
|
+
export type LoginData = z.infer<typeof loginSchema>;
|
|
9
|
+
export type RegisterData = z.infer<typeof registerSchema>;
|
|
10
|
+
export type RegisterHostData = z.infer<typeof registerHostSchema>;
|
|
11
|
+
export type UpdateGoogleUserOrganizationData = z.infer<typeof updateGoogleUserOrganizationSchema>;
|
|
12
|
+
|
|
13
|
+
// Payload interfaces for API
|
|
14
|
+
export interface LoginPayload {
|
|
15
|
+
email: string;
|
|
16
|
+
password: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface RegisterPayload {
|
|
20
|
+
firstName: string;
|
|
21
|
+
lastName: string;
|
|
22
|
+
email: string;
|
|
23
|
+
password: string;
|
|
24
|
+
confirmPassword: string;
|
|
25
|
+
organizationName?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RegisterHostPayload extends RegisterPayload {
|
|
29
|
+
organizationName: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface JwtTokenPayload {
|
|
33
|
+
sub: string;
|
|
34
|
+
email: string;
|
|
35
|
+
role: string;
|
|
36
|
+
firstName?: string;
|
|
37
|
+
lastName?: string;
|
|
38
|
+
organization?: string;
|
|
39
|
+
phone?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type Role = 'user' | 'host' | 'admin';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import zxcvbn from 'zxcvbn';
|
|
3
|
+
|
|
4
|
+
export const passwordSchema = z.string()
|
|
5
|
+
.min(8, 'Password must be at least 8 characters long')
|
|
6
|
+
.max(128, 'Password must be at most 128 characters long');
|
|
7
|
+
|
|
8
|
+
export const confirmPasswordSchema = z.string()
|
|
9
|
+
.min(8, 'Confirm password must be at least 8 characters long')
|
|
10
|
+
.max(128, 'Confirm password must be at most 128 characters long');
|
|
11
|
+
|
|
12
|
+
// Password strength validation
|
|
13
|
+
export const strongPasswordSchema = passwordSchema.refine(
|
|
14
|
+
(password) => zxcvbn(password).score >= 2,
|
|
15
|
+
{
|
|
16
|
+
message: 'Password must be strong (include uppercase, lowercase, numbers, and special characters)',
|
|
17
|
+
}
|
|
18
|
+
);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { EventType, DraftEventData, AgeRestriction, VenueType, DisplayTicket } from "./events.type";
|
|
2
|
+
|
|
3
|
+
export const MAX_TAGLINE_LENGTH = 150;
|
|
4
|
+
export const MAX_CATEGORIES = 3;
|
|
5
|
+
export const MAX_DESCRIPTION_LENGTH = 2000;
|
|
6
|
+
export const MAX_DOCUMENTS = 5;
|
|
7
|
+
export const SUPPORTED_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
|
|
8
|
+
export const MAX_FILE_SIZE_MB = 10;
|
|
9
|
+
export const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
|
|
10
|
+
export const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'application/pdf'];
|
|
11
|
+
export const ALLOWED_FILE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.pdf'];
|
|
12
|
+
|
|
13
|
+
export const CATEGORIES_BY_TYPE: Record<string, string[]> = {
|
|
14
|
+
concert: ['Rock', 'Pop', 'Jazz', 'Electronic', 'Indie', 'Metal', 'Acoustic', 'Classical'],
|
|
15
|
+
festival: ['Music', 'Food & Drink', 'Arts', 'Film', 'Culture', 'Tech', 'Family'],
|
|
16
|
+
conference: ['Technology', 'Business', 'Design', 'Marketing', 'Leadership', 'Startup', 'AI'],
|
|
17
|
+
theater: ['Drama', 'Comedy', 'Musical', 'Dance', 'Improv', 'Classical', 'Opera'],
|
|
18
|
+
sports: ['Football', 'Basketball', 'Tennis', 'Yoga', 'Fitness', 'Running', 'eSports'],
|
|
19
|
+
other: ['Community', 'Networking', 'Workshop', 'Meetup', 'Charity', 'Social', 'Party']
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export const EVENT_TYPES: Array<{
|
|
23
|
+
type: EventType;
|
|
24
|
+
icon: string;
|
|
25
|
+
label: string;
|
|
26
|
+
}> = [
|
|
27
|
+
{ type: 'concert', icon: 'Music', label: 'Concert' },
|
|
28
|
+
{ type: 'festival', icon: 'Tent', label: 'Festival' },
|
|
29
|
+
{ type: 'conference', icon: 'Mic2', label: 'Seminar' },
|
|
30
|
+
{ type: 'theater', icon: 'Theater', label: 'Performance' },
|
|
31
|
+
{ type: 'sports', icon: 'Trophy', label: 'Gala' },
|
|
32
|
+
{ type: 'other', icon: 'MoreHorizontal', label: 'Other' }
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
export const SUPPORTED_LANGUAGES = [
|
|
37
|
+
'English',
|
|
38
|
+
'Bangla'
|
|
39
|
+
] as const;
|
|
40
|
+
|
|
41
|
+
// Age restriction options with value (for form state) and label (for display)
|
|
42
|
+
export const AGE_RESTRICTIONS: Array<{
|
|
43
|
+
value: AgeRestriction;
|
|
44
|
+
label: string;
|
|
45
|
+
}> = [
|
|
46
|
+
{ value: 'all_ages', label: 'All Ages' },
|
|
47
|
+
{ value: '18+', label: '18+' },
|
|
48
|
+
{ value: '21+', label: '21+' },
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export const IMAGE_PLACEHOLDER_TEXT = {
|
|
54
|
+
dropzone: 'Drop your image here',
|
|
55
|
+
formats: 'Supports JPG, PNG, GIF (Max 5MB)',
|
|
56
|
+
change: 'Change Image'
|
|
57
|
+
} as const;
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
export const HOURS = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
63
|
+
export const MINUTES = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'));
|
|
64
|
+
export const AMPM = ['AM', 'PM'] as const;
|
|
65
|
+
export const TIME_PRESETS = [
|
|
66
|
+
{ label: '9 am', h: 9, m: '00', p: 'AM' },
|
|
67
|
+
{ label: '12 pm', h: 12, m: '00', p: 'PM' },
|
|
68
|
+
{ label: '4 pm', h: 4, m: '00', p: 'PM' },
|
|
69
|
+
{ label: '6 pm', h: 6, m: '00', p: 'PM' }
|
|
70
|
+
] as const;
|
|
71
|
+
|
|
72
|
+
export const VENUE_TYPES: Array<{
|
|
73
|
+
value: VenueType;
|
|
74
|
+
label: string;
|
|
75
|
+
icon: string;
|
|
76
|
+
}> = [
|
|
77
|
+
{ value: 'indoor', label: 'Indoor', icon: 'Building' },
|
|
78
|
+
{ value: 'outdoor', label: 'Outdoor', icon: 'Mountain' },
|
|
79
|
+
{ value: 'hybrid', label: 'Hybrid', icon: 'Building2' }
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
82
|
+
export const STEPS = [
|
|
83
|
+
{ id: 1, label: 'Basics', description: 'Event Basics' },
|
|
84
|
+
{ id: 2, label: 'Details', description: 'Event Details' },
|
|
85
|
+
{ id: 3, label: 'Logistics', description: 'Date & Venue' },
|
|
86
|
+
{ id: 4, label: 'Verify', description: 'Verification' },
|
|
87
|
+
{ id: 5, label: 'Tickets', description: 'Ticket Setup' },
|
|
88
|
+
{ id: 6, label: 'Review', description: 'Review & Publish' },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
export const PREDEFINED_BENEFITS = [
|
|
92
|
+
'Early entry',
|
|
93
|
+
'Access to general area',
|
|
94
|
+
'VIP seating',
|
|
95
|
+
'Meet & greet',
|
|
96
|
+
'Backstage access',
|
|
97
|
+
'Complimentary drink',
|
|
98
|
+
'Priority parking',
|
|
99
|
+
'Exclusive merchandise'
|
|
100
|
+
] as const;
|
|
101
|
+
|
|
102
|
+
// Helper function to get tomorrow's date in ISO format
|
|
103
|
+
const getTomorrowISOString = (): string => {
|
|
104
|
+
const tomorrow = new Date();
|
|
105
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
106
|
+
tomorrow.setHours(18, 0, 0, 0); // Default to 6 PM tomorrow
|
|
107
|
+
return tomorrow.toISOString();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getDayAfterTomorrowISOString = (): string => {
|
|
111
|
+
const dayAfterTomorrow = new Date();
|
|
112
|
+
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
|
|
113
|
+
dayAfterTomorrow.setHours(18, 0, 0, 0); // Default to 6 PM day after tomorrow
|
|
114
|
+
return dayAfterTomorrow.toISOString();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const INITIAL_DATA: DraftEventData = {
|
|
118
|
+
title: '',
|
|
119
|
+
tagline: '',
|
|
120
|
+
type: 'concert',
|
|
121
|
+
categories: [],
|
|
122
|
+
description: '',
|
|
123
|
+
media: {
|
|
124
|
+
coverImage: {
|
|
125
|
+
url: '',
|
|
126
|
+
thumbnailUrl: '',
|
|
127
|
+
alt: ''
|
|
128
|
+
},
|
|
129
|
+
gallery: []
|
|
130
|
+
},
|
|
131
|
+
language: 'English',
|
|
132
|
+
ageRestriction: 'all_ages',
|
|
133
|
+
dressCode: 'casual',
|
|
134
|
+
schedule: {
|
|
135
|
+
startDate: getTomorrowISOString(),
|
|
136
|
+
endDate: getDayAfterTomorrowISOString(),
|
|
137
|
+
},
|
|
138
|
+
venue: {
|
|
139
|
+
name: '',
|
|
140
|
+
type: 'indoor',
|
|
141
|
+
address: {
|
|
142
|
+
street: '',
|
|
143
|
+
city: '',
|
|
144
|
+
country: '',
|
|
145
|
+
},
|
|
146
|
+
coordinates: {
|
|
147
|
+
type: 'Point',
|
|
148
|
+
coordinates: [0, 0],
|
|
149
|
+
},
|
|
150
|
+
capacity: 100,
|
|
151
|
+
parking: false,
|
|
152
|
+
publicTransit: ''
|
|
153
|
+
},
|
|
154
|
+
organizer: {
|
|
155
|
+
role: 'event_organizer',
|
|
156
|
+
contactPerson: {
|
|
157
|
+
name: '',
|
|
158
|
+
email: '',
|
|
159
|
+
phone: '',
|
|
160
|
+
},
|
|
161
|
+
companyName: ''
|
|
162
|
+
},
|
|
163
|
+
verification: {
|
|
164
|
+
documents: [],
|
|
165
|
+
},
|
|
166
|
+
tickets: [],
|
|
167
|
+
termsAccepted: false,
|
|
168
|
+
legalPermissionAccepted: false,
|
|
169
|
+
platformTermsAccepted: false,
|
|
170
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { eventTypeSchema } from './utils/event.type.schema';
|
|
3
|
+
import { mediaSchema } from './utils/media.schema';
|
|
4
|
+
import { scheduleSchema } from './utils/schedule.schema';
|
|
5
|
+
import { venueSchema } from './utils/venue.schema';
|
|
6
|
+
import { organizerSchema } from './utils/organizer.schema';
|
|
7
|
+
import { documentSchema } from './utils/document.schema';
|
|
8
|
+
import { displayTicketSchema } from './utils/ticket.schema';
|
|
9
|
+
import { MAX_TAGLINE_LENGTH, MAX_CATEGORIES, MAX_DESCRIPTION_LENGTH, MAX_DOCUMENTS } from './events.constants';
|
|
10
|
+
import { ageRestrictionSchema } from './utils/age.restriction.schema';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// STEP SCHEMAS
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
// Step 1: Basics
|
|
18
|
+
export const stepBasicsSchema = z.object({
|
|
19
|
+
title: z.string({ required_error: 'Event title is required' }).min(10, 'Event title must be at least 10 characters').max(100, 'Title must be less than 100 characters'),
|
|
20
|
+
tagline: z.string().min(5, 'Tagline must be at least 5 characters').max(MAX_TAGLINE_LENGTH, `Tagline cannot exceed ${MAX_TAGLINE_LENGTH} characters`).optional(),
|
|
21
|
+
type: eventTypeSchema,
|
|
22
|
+
categories: z.array(z.string()).max(MAX_CATEGORIES, `Maximum ${MAX_CATEGORIES} categories allowed`).optional(),
|
|
23
|
+
}).passthrough();
|
|
24
|
+
|
|
25
|
+
// Step 2: Details
|
|
26
|
+
export const stepDetailsSchema = z.object({
|
|
27
|
+
media: mediaSchema,
|
|
28
|
+
description: z.string({ required_error: 'Event description is required' }).min(50, 'Description must be at least 50 characters').max(MAX_DESCRIPTION_LENGTH, `Description cannot exceed ${MAX_DESCRIPTION_LENGTH} characters`),
|
|
29
|
+
highlights: z.array(z.string().max(100, 'Each highlight cannot exceed 100 characters'), { required_error: 'Highlights must be an array of strings' }).max(10, 'Cannot have more than 10 highlights').optional(),
|
|
30
|
+
language: z.string({ required_error: 'Language is required' }),
|
|
31
|
+
ageRestriction: ageRestrictionSchema,
|
|
32
|
+
dressCode: z.enum(['casual', 'formal', 'semi-formal', 'other'], {required_error: "Dress code is required"}).optional(),
|
|
33
|
+
}).passthrough();
|
|
34
|
+
|
|
35
|
+
// Step 3: Logistics
|
|
36
|
+
export const stepLogisticsSchema = z.object({
|
|
37
|
+
schedule: scheduleSchema,
|
|
38
|
+
venue: venueSchema
|
|
39
|
+
}).passthrough().refine((data) => {
|
|
40
|
+
if (data.schedule.startDate && data.schedule.endDate) {
|
|
41
|
+
return new Date(data.schedule.endDate) > new Date(data.schedule.startDate);
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
}, {
|
|
45
|
+
message: "End date and time must be after start date and time",
|
|
46
|
+
path: ["schedule", "endDate"]
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Step 4: Verification
|
|
50
|
+
export const stepVerifySchema = z.object({
|
|
51
|
+
organizer: organizerSchema,
|
|
52
|
+
verification: z.object({
|
|
53
|
+
documents: z.array(documentSchema).min(1, 'At least one document is required').max(MAX_DOCUMENTS, `Maximum ${MAX_DOCUMENTS} documents allowed`)
|
|
54
|
+
})
|
|
55
|
+
}).passthrough();
|
|
56
|
+
|
|
57
|
+
// Step 5: Tickets
|
|
58
|
+
export const stepTicketsSchema = z.object({
|
|
59
|
+
tickets: z.array(displayTicketSchema).min(1, 'At least one ticket type is required')
|
|
60
|
+
}).passthrough().refine((data) => {
|
|
61
|
+
return data.tickets.length >= 1;
|
|
62
|
+
}, {
|
|
63
|
+
message: "At least one ticket type is required",
|
|
64
|
+
path: ["tickets"]
|
|
65
|
+
}).refine(data=> {
|
|
66
|
+
for (const ticket of data.tickets) {
|
|
67
|
+
if (ticket.salesWindow?.startDate && ticket.salesWindow?.endDate) {
|
|
68
|
+
if (new Date(ticket.salesWindow.endDate) <= new Date(ticket.salesWindow.startDate)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}, {
|
|
75
|
+
message: "End date and time must be after start date and time",
|
|
76
|
+
path: ["tickets", "salesWindow", "endDate"]
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Step 6: Review
|
|
80
|
+
export const stepReviewSchema = z.object({
|
|
81
|
+
termsAccepted: z.boolean().refine(val => val === true, {
|
|
82
|
+
message: 'You must accept all terms and conditions to publish this event'
|
|
83
|
+
}),
|
|
84
|
+
legalPermissionAccepted: z.boolean().refine(val => val === true, {
|
|
85
|
+
message: 'Legal permission confirmation is required'
|
|
86
|
+
}),
|
|
87
|
+
platformTermsAccepted: z.boolean().refine(val => val === true, {
|
|
88
|
+
message: 'Platform terms acceptance is required'
|
|
89
|
+
})
|
|
90
|
+
}).passthrough();
|
|
91
|
+
|
|
92
|
+
export const getEventSchema = z.object({
|
|
93
|
+
eventId: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Event not found').optional(),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
export const protectedEventSchema = z.object({
|
|
97
|
+
eventId: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Event not found'),
|
|
98
|
+
hostId: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Unauthorized'),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export const pendingApprovalEditSchema = z.object({
|
|
102
|
+
eventId: z.string({ required_error: 'Event not found' }).regex(/^[0-9a-fA-F]{24}$/, 'Event not found'),
|
|
103
|
+
hostId: z.string({ required_error: 'Unauthorized' }).regex(/^[0-9a-fA-F]{24}$/, 'Unauthorized'),
|
|
104
|
+
media: mediaSchema,
|
|
105
|
+
description: z.string({ required_error: 'Event description is required' }).min(50, 'Description must be at least 50 characters').max(MAX_DESCRIPTION_LENGTH, `Description cannot exceed ${MAX_DESCRIPTION_LENGTH} characters`),
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
export const approvedEventEditSchema = z.object({
|
|
109
|
+
eventId: z.string({ required_error: 'Event not found' }).regex(/^[0-9a-fA-F]{24}$/, 'Event not found'),
|
|
110
|
+
hostId: z.string({ required_error: 'Unauthorized' }).regex(/^[0-9a-fA-F]{24}$/, 'Unauthorized'),
|
|
111
|
+
media: mediaSchema,
|
|
112
|
+
description: z.string({ required_error: 'Event description is required' }).min(50, 'Description must be at least 50 characters').max(MAX_DESCRIPTION_LENGTH, `Description cannot exceed ${MAX_DESCRIPTION_LENGTH} characters`),
|
|
113
|
+
tickets: z.array(displayTicketSchema).min(1, 'At least one ticket type is required'),
|
|
114
|
+
}).refine(data=> {
|
|
115
|
+
for (const ticket of data.tickets) {
|
|
116
|
+
if (ticket.salesWindow?.startDate && ticket.salesWindow?.endDate) {
|
|
117
|
+
if (new Date(ticket.salesWindow.endDate) <= new Date(ticket.salesWindow.startDate)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}, {
|
|
124
|
+
message: "End date and time must be after start date and time",
|
|
125
|
+
path: ["tickets", "salesWindow", "endDate"]
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// =============================================================================
|
|
129
|
+
// COMPOSITE SCHEMAS
|
|
130
|
+
// =============================================================================
|
|
131
|
+
|
|
132
|
+
export const submitEventSchema = stepBasicsSchema
|
|
133
|
+
.merge(stepDetailsSchema)
|
|
134
|
+
.merge(stepLogisticsSchema._def.schema)
|
|
135
|
+
.merge(stepVerifySchema)
|
|
136
|
+
.merge(stepTicketsSchema._def.schema._def.schema)
|
|
137
|
+
.merge(stepReviewSchema)
|
|
138
|
+
.extend({
|
|
139
|
+
eventId: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Event not found').optional(),
|
|
140
|
+
hostId: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Unauthorized').optional(),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export const clientGetEventSchema = stepBasicsSchema
|
|
144
|
+
.merge(stepDetailsSchema)
|
|
145
|
+
.merge(stepLogisticsSchema._def.schema)
|
|
146
|
+
.merge(stepVerifySchema)
|
|
147
|
+
.merge(stepTicketsSchema._def.schema._def.schema)
|
|
148
|
+
.merge(stepReviewSchema)
|
|
149
|
+
.extend({
|
|
150
|
+
_id: z.string().regex(/^[0-9a-fA-F]{24}$/, 'Event not found'),
|
|
151
|
+
status: z.enum(['draft', 'pending_approval', 'approved', 'rejected', 'published', 'live', 'ended', 'cancelled'], { required_error: 'Event status is required' }).default('draft'),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
export const draftEventSchema = submitEventSchema
|
|
155
|
+
.partial()
|
|
156
|
+
.extend({
|
|
157
|
+
title: stepBasicsSchema.shape.title,
|
|
158
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { mediaSchema } from './utils/media.schema';
|
|
3
|
+
import { scheduleSchema } from './utils/schedule.schema';
|
|
4
|
+
import { venueSchema } from './utils/venue.schema';
|
|
5
|
+
import { organizerSchema } from './utils/organizer.schema';
|
|
6
|
+
import { documentSchema } from './utils/document.schema';
|
|
7
|
+
import { displayTicketSchema } from './utils/ticket.schema';
|
|
8
|
+
import { eventTypeSchema } from './utils/event.type.schema';
|
|
9
|
+
import { ageRestrictionSchema } from './utils/age.restriction.schema';
|
|
10
|
+
import { stepBasicsSchema, getEventSchema, protectedEventSchema, clientGetEventSchema, stepDetailsSchema, stepLogisticsSchema, stepVerifySchema, stepTicketsSchema, stepReviewSchema, submitEventSchema, draftEventSchema, pendingApprovalEditSchema, approvedEventEditSchema } from './events.schema';
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// TYPE EXPORTS
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
// Document type is now imported from media module
|
|
17
|
+
export type Media = z.infer<typeof mediaSchema>;
|
|
18
|
+
export type CoverImage = z.infer<typeof mediaSchema.shape.coverImage>;
|
|
19
|
+
export type Gallery = z.infer<typeof mediaSchema.shape.gallery>;
|
|
20
|
+
export type Organizer = z.infer<typeof organizerSchema>;
|
|
21
|
+
export type ContactPerson = z.infer<typeof organizerSchema.shape.contactPerson>;
|
|
22
|
+
export type Schedule = z.infer<typeof scheduleSchema>;
|
|
23
|
+
export type DisplayTicket = z.infer<typeof displayTicketSchema>;
|
|
24
|
+
export type Price = z.infer<typeof displayTicketSchema.shape.price>;
|
|
25
|
+
export type SalesWindow = z.infer<typeof displayTicketSchema.shape.salesWindow>;
|
|
26
|
+
export type Limits = z.infer<typeof displayTicketSchema.shape.limits>;
|
|
27
|
+
export type Venue = z.infer<typeof venueSchema>;
|
|
28
|
+
export type VenueType = z.infer<typeof venueSchema.shape.type>;
|
|
29
|
+
export type Address = z.infer<typeof venueSchema.shape.address>;
|
|
30
|
+
export type Document = z.infer<typeof documentSchema>;
|
|
31
|
+
|
|
32
|
+
// Shared enum types
|
|
33
|
+
export type EventType = z.infer<typeof eventTypeSchema>;
|
|
34
|
+
export type AgeRestriction = z.infer<typeof ageRestrictionSchema>;
|
|
35
|
+
|
|
36
|
+
// Step data types
|
|
37
|
+
export type StepBasicsData = z.infer<typeof stepBasicsSchema>;
|
|
38
|
+
export type StepDetailsData = z.infer<typeof stepDetailsSchema>;
|
|
39
|
+
export type StepLogisticsData = z.infer<typeof stepLogisticsSchema>;
|
|
40
|
+
export type StepVerifyData = z.infer<typeof stepVerifySchema>;
|
|
41
|
+
export type StepTicketsData = z.infer<typeof stepTicketsSchema>;
|
|
42
|
+
export type StepReviewData = z.infer<typeof stepReviewSchema>;
|
|
43
|
+
|
|
44
|
+
// Composite types
|
|
45
|
+
export type SubmitEventData = z.infer<typeof submitEventSchema>;
|
|
46
|
+
export type DraftEventData = z.infer<typeof draftEventSchema>;
|
|
47
|
+
export type GetEventData = z.infer<typeof getEventSchema>;
|
|
48
|
+
export type ProtectedEventData = z.infer<typeof protectedEventSchema>;
|
|
49
|
+
export type ClientGetEventData = z.infer<typeof clientGetEventSchema>;
|
|
50
|
+
export type PendingApprovalEditData = z.infer<typeof pendingApprovalEditSchema>;
|
|
51
|
+
export type ApprovedEventEditData = z.infer<typeof approvedEventEditSchema>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export * from './events.schema';
|
|
2
|
-
export * from './events.type';
|
|
3
|
-
export * from './events.utils.schema';
|
|
1
|
+
export * from './events.schema';
|
|
2
|
+
export * from './events.type';
|
|
3
|
+
export * from './events.utils.schema';
|
|
4
|
+
export * from './events.constants';
|