From d8aa9956d0e28d80d6ed2c2cba0feea236d60342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Perret?= Date: Tue, 1 Sep 2026 17:18:28 +0200 Subject: [PATCH] =?UTF-8?q?feat=20:=20Cr=C3=A9ation=20de=20toutes=20les=20?= =?UTF-8?q?entit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 18 +++++++++--- package.json | 3 +- src/models/_shared.ts | 17 ++++++++++++ src/models/animators.ts | 16 +++++++++++ src/models/comment_likes.ts | 11 ++++++++ src/models/comments.ts | 15 ++++++++++ src/models/event_external_links.ts | 13 +++++++++ src/models/event_hashtags.ts | 10 +++++++ src/models/event_images.ts | 14 ++++++++++ src/models/event_lineup.ts | 18 ++++++++++++ src/models/event_stats_snapshots.ts | 15 ++++++++++ src/models/event_themes.ts | 10 +++++++ src/models/events.ts | 40 +++++++++++++++++++++++++++ src/models/hashtags.ts | 10 +++++++ src/models/index.ts | 30 ++++++++++++++++++++ src/models/organizer_members.ts | 20 ++++++++++++++ src/models/organizer_subscriptions.ts | 21 ++++++++++++++ src/models/organizers.ts | 23 +++++++++++++++ src/models/plans.ts | 16 +++++++++++ src/models/post_likes.ts | 11 ++++++++ src/models/post_media.ts | 16 +++++++++++ src/models/posts.ts | 31 +++++++++++++++++++++ src/models/search_history.ts | 12 ++++++++ src/models/social_auth_providers.ts | 13 +++++++++ src/models/themes.ts | 15 ++++++++++ src/models/tickets.ts | 22 +++++++++++++++ src/models/user_animator_follows.ts | 11 ++++++++ src/models/user_event_interactions.ts | 19 +++++++++++++ src/models/user_event_shares.ts | 12 ++++++++ src/models/user_organizer_follows.ts | 11 ++++++++ src/models/user_theme_preferences.ts | 10 +++++++ src/models/users.ts | 31 +++++++++++++++++++++ 32 files changed, 529 insertions(+), 5 deletions(-) create mode 100644 src/models/_shared.ts create mode 100644 src/models/animators.ts create mode 100644 src/models/comment_likes.ts create mode 100644 src/models/comments.ts create mode 100644 src/models/event_external_links.ts create mode 100644 src/models/event_hashtags.ts create mode 100644 src/models/event_images.ts create mode 100644 src/models/event_lineup.ts create mode 100644 src/models/event_stats_snapshots.ts create mode 100644 src/models/event_themes.ts create mode 100644 src/models/events.ts create mode 100644 src/models/hashtags.ts create mode 100644 src/models/index.ts create mode 100644 src/models/organizer_members.ts create mode 100644 src/models/organizer_subscriptions.ts create mode 100644 src/models/organizers.ts create mode 100644 src/models/plans.ts create mode 100644 src/models/post_likes.ts create mode 100644 src/models/post_media.ts create mode 100644 src/models/posts.ts create mode 100644 src/models/search_history.ts create mode 100644 src/models/social_auth_providers.ts create mode 100644 src/models/themes.ts create mode 100644 src/models/tickets.ts create mode 100644 src/models/user_animator_follows.ts create mode 100644 src/models/user_event_interactions.ts create mode 100644 src/models/user_event_shares.ts create mode 100644 src/models/user_organizer_follows.ts create mode 100644 src/models/user_theme_preferences.ts create mode 100644 src/models/users.ts diff --git a/package-lock.json b/package-lock.json index 89b789b..fee8320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,8 @@ "react-native-svg": "15.15.4", "react-native-web": "~0.21.0", "react-native-worklets": "0.8.3", - "tailwindcss": "^3.4.19" + "tailwindcss": "^3.4.19", + "zod": "^4.5.4" }, "devDependencies": { "@types/react": "~19.2.2", @@ -5329,6 +5330,15 @@ } } }, + "node_modules/expo/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -10156,9 +10166,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz", + "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index b30760f..7c9c882 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "react-native-svg": "15.15.4", "react-native-web": "~0.21.0", "react-native-worklets": "0.8.3", - "tailwindcss": "^3.4.19" + "tailwindcss": "^3.4.19", + "zod": "^4.5.4" }, "devDependencies": { "@types/react": "~19.2.2", diff --git a/src/models/_shared.ts b/src/models/_shared.ts new file mode 100644 index 0000000..8318132 --- /dev/null +++ b/src/models/_shared.ts @@ -0,0 +1,17 @@ +import { z } from 'zod'; + +export const uuidSchema = z.string().uuid(); + +export const timestampSchema = z.coerce.date(); + +export const sqlDateSchema = z + .string() + .regex(/^\d{4}-\d{2}-\d{2}$/, 'Expected date format YYYY-MM-DD'); + +export const nullableText = z.string().trim().min(1).nullable(); + +export const nullableUrl = z.string().url().nullable(); + +export const nullableLatitude = z.number().min(-90).max(90).nullable(); + +export const nullableLongitude = z.number().min(-180).max(180).nullable(); diff --git a/src/models/animators.ts b/src/models/animators.ts new file mode 100644 index 0000000..5a7ad59 --- /dev/null +++ b/src/models/animators.ts @@ -0,0 +1,16 @@ +import { z } from 'zod'; + +import { nullableUrl, timestampSchema, uuidSchema } from './_shared'; + +export const animatorSchema = z.object({ + id: uuidSchema, + name: z.string().trim().min(1).max(255), + profile_picture: nullableUrl, + genre: z.string().trim().min(1).max(100).nullable(), + city: z.string().trim().min(1).max(100).nullable(), + bio: z.string().trim().min(1).nullable(), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type Animator = z.infer; diff --git a/src/models/comment_likes.ts b/src/models/comment_likes.ts new file mode 100644 index 0000000..4ad519f --- /dev/null +++ b/src/models/comment_likes.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const commentLikeSchema = z.object({ + user_id: uuidSchema, + comment_id: uuidSchema, + created_at: timestampSchema, +}); + +export type CommentLike = z.infer; diff --git a/src/models/comments.ts b/src/models/comments.ts new file mode 100644 index 0000000..4b1d3ba --- /dev/null +++ b/src/models/comments.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const commentSchema = z.object({ + id: uuidSchema, + post_id: uuidSchema, + user_id: uuidSchema, + parent_comment_id: uuidSchema.nullable(), + content: z.string().trim().min(1), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type Comment = z.infer; diff --git a/src/models/event_external_links.ts b/src/models/event_external_links.ts new file mode 100644 index 0000000..a7ac020 --- /dev/null +++ b/src/models/event_external_links.ts @@ -0,0 +1,13 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const eventExternalLinkSchema = z.object({ + id: uuidSchema, + event_id: uuidSchema, + url: z.string().trim().min(1), + label: z.string().trim().min(1).max(100).nullable(), + display_order: z.number().int().default(0), +}); + +export type EventExternalLink = z.infer; diff --git a/src/models/event_hashtags.ts b/src/models/event_hashtags.ts new file mode 100644 index 0000000..105e990 --- /dev/null +++ b/src/models/event_hashtags.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const eventHashtagSchema = z.object({ + event_id: uuidSchema, + hashtag_id: uuidSchema, +}); + +export type EventHashtag = z.infer; diff --git a/src/models/event_images.ts b/src/models/event_images.ts new file mode 100644 index 0000000..3869f57 --- /dev/null +++ b/src/models/event_images.ts @@ -0,0 +1,14 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const eventImageSchema = z.object({ + id: uuidSchema, + event_id: uuidSchema, + url: z.string().url(), + is_cover: z.boolean().default(false), + display_order: z.number().int().default(0), + created_at: timestampSchema, +}); + +export type EventImage = z.infer; diff --git a/src/models/event_lineup.ts b/src/models/event_lineup.ts new file mode 100644 index 0000000..fbe0716 --- /dev/null +++ b/src/models/event_lineup.ts @@ -0,0 +1,18 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const eventLineupRoleSchema = z.enum(['HEADLINER', 'OPENING', 'CLOSING']); + +export const eventLineupSchema = z.object({ + id: uuidSchema, + event_id: uuidSchema, + animator_id: uuidSchema, + stage_name: z.string().trim().min(1).max(100).nullable(), + start_time: timestampSchema.nullable(), + end_time: timestampSchema.nullable(), + role: eventLineupRoleSchema.nullable(), + display_order: z.number().int().default(0), +}); + +export type EventLineup = z.infer; diff --git a/src/models/event_stats_snapshots.ts b/src/models/event_stats_snapshots.ts new file mode 100644 index 0000000..316f01b --- /dev/null +++ b/src/models/event_stats_snapshots.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +import { sqlDateSchema, uuidSchema } from './_shared'; + +export const eventStatsSnapshotSchema = z.object({ + id: uuidSchema, + event_id: uuidSchema, + snapshot_date: sqlDateSchema, + view_count: z.number().int().min(0).default(0), + participant_count: z.number().int().min(0).default(0), + interested_count: z.number().int().min(0).default(0), + share_count: z.number().int().min(0).default(0), +}); + +export type EventStatsSnapshot = z.infer; diff --git a/src/models/event_themes.ts b/src/models/event_themes.ts new file mode 100644 index 0000000..73181ad --- /dev/null +++ b/src/models/event_themes.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const eventThemeSchema = z.object({ + event_id: uuidSchema, + theme_id: uuidSchema, +}); + +export type EventTheme = z.infer; diff --git a/src/models/events.ts b/src/models/events.ts new file mode 100644 index 0000000..a49333c --- /dev/null +++ b/src/models/events.ts @@ -0,0 +1,40 @@ +import { z } from 'zod'; + +import { + nullableLatitude, + nullableLongitude, + nullableText, + timestampSchema, + uuidSchema, +} from './_shared'; + +export const eventStatusSchema = z.enum(['DRAFT', 'PUBLISHED', 'CANCELLED']); + +export const eventSchema = z.object({ + id: uuidSchema, + organizer_id: uuidSchema, + name: z.string().trim().min(1).max(255), + description: z.string().trim().max(600).nullable(), + start_date: timestampSchema, + end_date: timestampSchema, + doors_open_time: timestampSchema.nullable(), + min_age: z.number().int().min(0).nullable(), + address: nullableText, + city: z.string().trim().min(1).max(100).nullable(), + latitude: nullableLatitude, + longitude: nullableLongitude, + price_presale: z.number().min(0).nullable(), + price_door: z.number().min(0).nullable(), + is_free: z.boolean().default(false), + presale_total: z.number().int().min(0).nullable(), + presale_sold: z.number().int().min(0).default(0), + ticketing_enabled: z.boolean().default(false), + ticketing_commission: z.number().min(0).max(100).nullable(), + status: eventStatusSchema, + featured_image_id: uuidSchema.nullable(), + published_at: timestampSchema.nullable(), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type Event = z.infer; diff --git a/src/models/hashtags.ts b/src/models/hashtags.ts new file mode 100644 index 0000000..44ba07a --- /dev/null +++ b/src/models/hashtags.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const hashtagSchema = z.object({ + id: uuidSchema, + name: z.string().trim().min(1).max(100), +}); + +export type Hashtag = z.infer; diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..3a12870 --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,30 @@ +export * from './_shared'; +export * from './animators'; +export * from './comment_likes'; +export * from './comments'; +export * from './event_external_links'; +export * from './event_hashtags'; +export * from './event_images'; +export * from './event_lineup'; +export * from './event_stats_snapshots'; +export * from './event_themes'; +export * from './events'; +export * from './hashtags'; +export * from './organizer_members'; +export * from './organizer_subscriptions'; +export * from './organizers'; +export * from './plans'; +export * from './post_likes'; +export * from './post_media'; +export * from './posts'; +export * from './search_history'; +export * from './social_auth_providers'; +export * from './themes'; +export * from './tickets'; +export * from './user_animator_follows'; +export * from './user_event_interactions'; +export * from './user_event_shares'; +export * from './user_organizer_follows'; +export * from './user_theme_preferences'; +export * from './users'; + diff --git a/src/models/organizer_members.ts b/src/models/organizer_members.ts new file mode 100644 index 0000000..b31bb76 --- /dev/null +++ b/src/models/organizer_members.ts @@ -0,0 +1,20 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const organizerMemberRoleSchema = z.enum(['ADMIN', 'EDITOR']); + +export const organizerMemberStatusSchema = z.enum(['ACTIVE', 'PENDING']); + +export const organizerMemberSchema = z.object({ + id: uuidSchema, + organizer_id: uuidSchema, + user_id: uuidSchema.nullable(), + email: z.string().trim().email().max(255), + role: organizerMemberRoleSchema, + status: organizerMemberStatusSchema, + invited_at: timestampSchema, + joined_at: timestampSchema.nullable(), +}); + +export type OrganizerMember = z.infer; diff --git a/src/models/organizer_subscriptions.ts b/src/models/organizer_subscriptions.ts new file mode 100644 index 0000000..d55d131 --- /dev/null +++ b/src/models/organizer_subscriptions.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; + +import { sqlDateSchema, timestampSchema, uuidSchema } from './_shared'; + +export const organizerSubscriptionStatusSchema = z.enum([ + 'ACTIVE', + 'CANCELLED', + 'EXPIRED', +]); + +export const organizerSubscriptionSchema = z.object({ + id: uuidSchema, + organizer_id: uuidSchema, + plan_id: uuidSchema, + status: organizerSubscriptionStatusSchema, + started_at: timestampSchema, + renewal_date: sqlDateSchema.nullable(), + cancelled_at: timestampSchema.nullable(), +}); + +export type OrganizerSubscription = z.infer; diff --git a/src/models/organizers.ts b/src/models/organizers.ts new file mode 100644 index 0000000..2654c10 --- /dev/null +++ b/src/models/organizers.ts @@ -0,0 +1,23 @@ +import { z } from 'zod'; + +import { nullableUrl, timestampSchema, uuidSchema } from './_shared'; + +export const organizerSchema = z.object({ + id: uuidSchema, + name: z.string().trim().min(1).max(255), + email: z.string().trim().email().max(255), + profile_picture: nullableUrl, + cover_picture: nullableUrl, + city: z.string().trim().min(1).max(100).nullable(), + is_verified: z.boolean().default(false), + verified_at: timestampSchema.nullable(), + verified_by: uuidSchema.nullable(), + instagram_handle: z.string().trim().min(1).max(100).nullable(), + tiktok_handle: z.string().trim().min(1).max(100).nullable(), + facebook_handle: z.string().trim().min(1).max(100).nullable(), + plan_id: uuidSchema.nullable(), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type Organizer = z.infer; diff --git a/src/models/plans.ts b/src/models/plans.ts new file mode 100644 index 0000000..094bb60 --- /dev/null +++ b/src/models/plans.ts @@ -0,0 +1,16 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const planNameSchema = z.enum(['FREE', 'PRO', 'TICKETING']); + +export const planSchema = z.object({ + id: uuidSchema, + name: planNameSchema, + price_monthly: z.number().min(0), + max_active_events: z.number().int().min(0).nullable(), + ticketing_enabled: z.boolean().default(false), + ticketing_commission: z.number().min(0).max(100).nullable(), +}); + +export type Plan = z.infer; diff --git a/src/models/post_likes.ts b/src/models/post_likes.ts new file mode 100644 index 0000000..eea8d34 --- /dev/null +++ b/src/models/post_likes.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const postLikeSchema = z.object({ + user_id: uuidSchema, + post_id: uuidSchema, + created_at: timestampSchema, +}); + +export type PostLike = z.infer; diff --git a/src/models/post_media.ts b/src/models/post_media.ts new file mode 100644 index 0000000..fffc74d --- /dev/null +++ b/src/models/post_media.ts @@ -0,0 +1,16 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const postMediaTypeSchema = z.enum(['IMAGE', 'VIDEO']); + +export const postMediaSchema = z.object({ + id: uuidSchema, + post_id: uuidSchema, + url: z.string().url(), + type: postMediaTypeSchema, + duration_seconds: z.number().int().min(0).nullable(), + display_order: z.number().int().default(0), +}); + +export type PostMedia = z.infer; diff --git a/src/models/posts.ts b/src/models/posts.ts new file mode 100644 index 0000000..0f0b2fb --- /dev/null +++ b/src/models/posts.ts @@ -0,0 +1,31 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const postTypeSchema = z.enum([ + 'TEXT', + 'PHOTO', + 'VIDEO', + 'ANNOUNCEMENT', + 'TEASER', +]); + +export const postStatusSchema = z.enum(['DRAFT', 'SCHEDULED', 'PUBLISHED']); + +export const postSchema = z.object({ + id: uuidSchema, + organizer_id: uuidSchema, + event_id: uuidSchema.nullable(), + content: z.string().trim().max(500).nullable(), + type: postTypeSchema, + status: postStatusSchema, + scheduled_at: timestampSchema.nullable(), + published_at: timestampSchema.nullable(), + rediffusion_instagram: z.boolean().default(false), + rediffusion_tiktok: z.boolean().default(false), + rediffusion_facebook: z.boolean().default(false), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type Post = z.infer; diff --git a/src/models/search_history.ts b/src/models/search_history.ts new file mode 100644 index 0000000..a9564c9 --- /dev/null +++ b/src/models/search_history.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const searchHistorySchema = z.object({ + id: uuidSchema, + user_id: uuidSchema, + query: z.string().trim().min(1).max(255), + searched_at: timestampSchema, +}); + +export type SearchHistory = z.infer; diff --git a/src/models/social_auth_providers.ts b/src/models/social_auth_providers.ts new file mode 100644 index 0000000..5dcf581 --- /dev/null +++ b/src/models/social_auth_providers.ts @@ -0,0 +1,13 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const socialAuthProviderSchema = z.object({ + id: uuidSchema, + user_id: uuidSchema, + provider: z.enum(['google', 'apple']), + provider_user_id: z.string().trim().min(1).max(255), + created_at: timestampSchema, +}); + +export type SocialAuthProvider = z.infer; diff --git a/src/models/themes.ts b/src/models/themes.ts new file mode 100644 index 0000000..82f2697 --- /dev/null +++ b/src/models/themes.ts @@ -0,0 +1,15 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const themesSchema = z.object({ + id: uuidSchema, + name: z.string().trim().min(1).max(100), + color_hex: z + .string() + .regex(/^#[0-9A-Fa-f]{6}$/, 'Expected color format #RRGGBB') + .nullable(), + display_order: z.number().int().default(0), +}); + +export type Theme = z.infer; diff --git a/src/models/tickets.ts b/src/models/tickets.ts new file mode 100644 index 0000000..43006b6 --- /dev/null +++ b/src/models/tickets.ts @@ -0,0 +1,22 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const ticketTypeSchema = z.enum(['PRESALE', 'DOOR']); + +export const ticketStatusSchema = z.enum(['VALID', 'USED', 'CANCELLED']); + +export const ticketSchema = z.object({ + id: uuidSchema, + event_id: uuidSchema, + user_id: uuidSchema, + type: ticketTypeSchema, + price_paid: z.number().min(0), + bahla_commission: z.number().min(0), + status: ticketStatusSchema, + purchased_at: timestampSchema, + used_at: timestampSchema.nullable(), + qr_code: z.string().trim().min(1).nullable(), +}); + +export type Ticket = z.infer; diff --git a/src/models/user_animator_follows.ts b/src/models/user_animator_follows.ts new file mode 100644 index 0000000..4c57d49 --- /dev/null +++ b/src/models/user_animator_follows.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const userAnimatorFollowSchema = z.object({ + user_id: uuidSchema, + animator_id: uuidSchema, + created_at: timestampSchema, +}); + +export type UserAnimatorFollow = z.infer; diff --git a/src/models/user_event_interactions.ts b/src/models/user_event_interactions.ts new file mode 100644 index 0000000..b7454a1 --- /dev/null +++ b/src/models/user_event_interactions.ts @@ -0,0 +1,19 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const userEventInteractionStatusSchema = z.enum([ + 'PARTICIPATING', + 'INTERESTED', + 'SAVED', +]); + +export const userEventInteractionSchema = z.object({ + user_id: uuidSchema, + event_id: uuidSchema, + status: userEventInteractionStatusSchema, + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type UserEventInteraction = z.infer; diff --git a/src/models/user_event_shares.ts b/src/models/user_event_shares.ts new file mode 100644 index 0000000..ba03157 --- /dev/null +++ b/src/models/user_event_shares.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const userEventShareSchema = z.object({ + id: uuidSchema, + user_id: uuidSchema.nullable(), + event_id: uuidSchema, + shared_at: timestampSchema, +}); + +export type UserEventShare = z.infer; diff --git a/src/models/user_organizer_follows.ts b/src/models/user_organizer_follows.ts new file mode 100644 index 0000000..9c334e1 --- /dev/null +++ b/src/models/user_organizer_follows.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +import { timestampSchema, uuidSchema } from './_shared'; + +export const userOrganizerFollowSchema = z.object({ + user_id: uuidSchema, + organizer_id: uuidSchema, + created_at: timestampSchema, +}); + +export type UserOrganizerFollow = z.infer; diff --git a/src/models/user_theme_preferences.ts b/src/models/user_theme_preferences.ts new file mode 100644 index 0000000..0126f66 --- /dev/null +++ b/src/models/user_theme_preferences.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +import { uuidSchema } from './_shared'; + +export const userThemePreferenceSchema = z.object({ + user_id: uuidSchema, + theme_id: uuidSchema, +}); + +export type UserThemePreference = z.infer; diff --git a/src/models/users.ts b/src/models/users.ts new file mode 100644 index 0000000..e31c4fc --- /dev/null +++ b/src/models/users.ts @@ -0,0 +1,31 @@ +import { z } from 'zod'; + +import { + nullableLatitude, + nullableLongitude, + nullableText, + nullableUrl, + timestampSchema, + uuidSchema, +} from './_shared'; + +export const userSchema = z.object({ + id: uuidSchema, + first_name: z.string().trim().min(1).max(100), + last_name: z.string().trim().min(1).max(100), + email: z.string().trim().email().max(255), + password_hash: z.string().trim().min(1).max(255).nullable(), + profile_picture: nullableUrl, + address: nullableText, + city: z.string().trim().min(1).max(100).nullable(), + latitude: nullableLatitude, + longitude: nullableLongitude, + default_radius_km: z.number().int().min(0).default(25), + language: z.string().trim().min(2).max(10).default('fr'), + notifications_enabled: z.boolean().default(true), + calendar_sync_enabled: z.boolean().default(false), + created_at: timestampSchema, + updated_at: timestampSchema, +}); + +export type User = z.infer;