mirror of
https://github.com/SamyRai/tercul-frontend.git
synced 2025-12-27 03:41:34 +00:00
- Enhanced annotation system with improved inline editing - Updated author components with new card and header designs - Improved reading view with enhanced line numbering and controls - Added new blog management features and tag management - Updated UI components with improved accessibility and styling - Enhanced search functionality with better filtering - Added new dashboard features and activity feeds - Improved translation selector and work comparison tools - Updated GraphQL integration and API hooks - Enhanced responsive design and mobile experience
642 lines
18 KiB
TypeScript
642 lines
18 KiB
TypeScript
import { z } from "zod";
|
|
|
|
// Enums for GraphQL/API
|
|
export const roleEnum = z.enum([
|
|
"user",
|
|
"contributor",
|
|
"reviewer",
|
|
"editor",
|
|
"admin",
|
|
]);
|
|
|
|
export const workTypeEnum = z.enum([
|
|
"poem",
|
|
"story",
|
|
"novel",
|
|
"play",
|
|
"essay",
|
|
"other",
|
|
]);
|
|
|
|
export const contributionStatusEnum = z.enum([
|
|
"draft",
|
|
"submitted",
|
|
"under_review",
|
|
"approved",
|
|
"rejected",
|
|
]);
|
|
|
|
// Core entity schemas for GraphQL/API
|
|
export const userSchema = z.object({
|
|
id: z.string(),
|
|
username: z.string(),
|
|
email: z.string(),
|
|
displayName: z.string().optional(),
|
|
firstName: z.string().optional(),
|
|
lastName: z.string().optional(),
|
|
bio: z.string().optional(),
|
|
avatar: z.string().optional(),
|
|
role: roleEnum,
|
|
verified: z.boolean().optional(),
|
|
active: z.boolean().optional(),
|
|
lastLoginAt: z.string().optional(),
|
|
createdAt: z.string(), // ISO date string
|
|
updatedAt: z.string().optional(),
|
|
countryId: z.string().optional(),
|
|
cityId: z.string().optional(),
|
|
});
|
|
|
|
export const authorSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
slug: z.string(),
|
|
birthYear: z.number().optional(),
|
|
deathYear: z.number().optional(),
|
|
country: z.string().optional(),
|
|
biography: z.string().optional(),
|
|
portrait: z.string().optional(),
|
|
createdAt: z.string(),
|
|
createdBy: z.string().optional(),
|
|
updatedAt: z.string().optional(),
|
|
countryId: z.string().optional(),
|
|
cityId: z.string().optional(),
|
|
copyrightId: z.string().optional(),
|
|
});
|
|
|
|
export const workSchema = z.object({
|
|
id: z.string(),
|
|
title: z.string(),
|
|
slug: z.string(),
|
|
authorId: z.string(),
|
|
year: z.number().optional(),
|
|
type: workTypeEnum,
|
|
language: z.string(),
|
|
content: z.string(),
|
|
description: z.string().optional(),
|
|
createdAt: z.string(),
|
|
createdBy: z.string().optional(),
|
|
updatedAt: z.string().optional(),
|
|
tags: z.array(z.string()).optional(), // Array of tag IDs
|
|
likes: z.number().optional(),
|
|
views: z.number().optional(),
|
|
author: authorSchema.optional(), // For denormalized author info
|
|
readabilityScore: z.number().optional(),
|
|
copyrightId: z.string().optional(),
|
|
});
|
|
|
|
export const translationSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
title: z.string(),
|
|
language: z.string(),
|
|
content: z.string(),
|
|
translatorId: z.string(),
|
|
year: z.number().optional(),
|
|
notes: z.string().optional(),
|
|
description: z.string().optional(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const tagSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
type: z.string(), // genre, period, theme, etc.
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const bookmarkSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
workId: z.string(),
|
|
note: z.string().optional(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const commentSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
workId: z.string().optional(),
|
|
translationId: z.string().optional(),
|
|
lineNumber: z.number().optional(),
|
|
content: z.string(),
|
|
parentId: z.string().optional(),
|
|
entityType: z.string().optional(), // 'work', 'translation', 'blogPost', etc.
|
|
entityId: z.string().optional(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const likeSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
entityType: z.string(), // 'work', 'translation', 'comment'
|
|
entityId: z.string(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const collectionSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
slug: z.string(),
|
|
description: z.string().optional(),
|
|
userId: z.string(),
|
|
isPublic: z.boolean(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const collectionItemSchema = z.object({
|
|
id: z.string(),
|
|
collectionId: z.string(),
|
|
workId: z.string(),
|
|
order: z.number(),
|
|
addedAt: z.string(),
|
|
});
|
|
|
|
export const timelineEventSchema = z.object({
|
|
id: z.string(),
|
|
authorId: z.string(),
|
|
year: z.number(),
|
|
title: z.string(),
|
|
description: z.string().optional(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const blogPostSchema = z.object({
|
|
id: z.string(),
|
|
title: z.string(),
|
|
slug: z.string(),
|
|
content: z.string(),
|
|
authorId: z.string(),
|
|
excerpt: z.string().optional(),
|
|
publishedAt: z.string().optional(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const readingProgressSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
workId: z.string(),
|
|
translationId: z.string().optional(),
|
|
progress: z.number().min(0).max(100), // percentage
|
|
lastReadAt: z.string(),
|
|
});
|
|
|
|
export const annotationSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
translationId: z.string().optional(),
|
|
lineNumber: z.number().optional(),
|
|
content: z.string(),
|
|
type: z.string(), // 'context', 'analysis', 'translation', etc.
|
|
userId: z.string(),
|
|
isOfficial: z.boolean(),
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
export const analysisResultSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
type: z.string(), // 'sentiment', 'linguistics', 'themes', 'poetic', etc.
|
|
data: z.record(z.string(), z.unknown()), // flexible data structure
|
|
createdAt: z.string(),
|
|
});
|
|
|
|
// New schemas for GraphQL alignment
|
|
export const countrySchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
code: z.string(),
|
|
language: z.string(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const citySchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
countryId: z.string(),
|
|
language: z.string(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const bookSchema = z.object({
|
|
id: z.string(),
|
|
title: z.string(),
|
|
slug: z.string(),
|
|
language: z.string(),
|
|
authorId: z.string(),
|
|
copyrightId: z.string().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const copyrightSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
language: z.string(),
|
|
details: z.string().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const contributionSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
status: contributionStatusEnum,
|
|
userId: z.string(),
|
|
workId: z.string().optional(),
|
|
translationId: z.string().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const userProfileSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
phoneNumber: z.string().optional(),
|
|
website: z.string().optional(),
|
|
twitter: z.string().optional(),
|
|
facebook: z.string().optional(),
|
|
linkedIn: z.string().optional(),
|
|
github: z.string().optional(),
|
|
preferences: z.record(z.string(), z.unknown()).optional(),
|
|
settings: z.record(z.string(), z.unknown()).optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const readabilityScoreSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
score: z.number(),
|
|
language: z.string(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const writingStyleSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
name: z.string(),
|
|
language: z.string(),
|
|
characteristics: z.record(z.string(), z.unknown()).optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const emotionSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
workId: z.string().optional(),
|
|
userId: z.string().optional(),
|
|
collectionId: z.string().optional(),
|
|
language: z.string(),
|
|
intensity: z.number().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const conceptSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
description: z.string().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const topicClusterSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
description: z.string().optional(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const workStatsSchema = z.object({
|
|
id: z.string(),
|
|
workId: z.string(),
|
|
views: z.number(),
|
|
likes: z.number(),
|
|
bookmarks: z.number(),
|
|
comments: z.number(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
export const userStatsSchema = z.object({
|
|
id: z.string(),
|
|
userId: z.string(),
|
|
activity: z.number(),
|
|
contributions: z.number(),
|
|
likes: z.number(),
|
|
comments: z.number(),
|
|
createdAt: z.string(),
|
|
updatedAt: z.string().optional(),
|
|
});
|
|
|
|
// Input schemas for GraphQL mutations/API endpoints
|
|
export const createUserSchema = userSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
role: true, // Role assigned by system
|
|
});
|
|
|
|
export const createAuthorSchema = authorSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createWorkSchema = workSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
author: true, // Not included in creation
|
|
});
|
|
|
|
export const createTranslationSchema = translationSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createTagSchema = tagSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createBookmarkSchema = bookmarkSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createCommentSchema = commentSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createLikeSchema = likeSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createCollectionSchema = collectionSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createCollectionItemSchema = collectionItemSchema.omit({
|
|
id: true,
|
|
addedAt: true,
|
|
});
|
|
|
|
export const createTimelineEventSchema = timelineEventSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createBlogPostSchema = blogPostSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createReadingProgressSchema = readingProgressSchema.omit({
|
|
id: true,
|
|
lastReadAt: true,
|
|
});
|
|
|
|
export const createAnnotationSchema = annotationSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
export const createAnalysisResultSchema = analysisResultSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
});
|
|
|
|
// New create schemas for GraphQL alignment
|
|
export const createCountrySchema = countrySchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createCitySchema = citySchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createBookSchema = bookSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createCopyrightSchema = copyrightSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createContributionSchema = contributionSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createUserProfileSchema = userProfileSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createReadabilityScoreSchema = readabilityScoreSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createWritingStyleSchema = writingStyleSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createEmotionSchema = emotionSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createConceptSchema = conceptSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createTopicClusterSchema = topicClusterSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createWorkStatsSchema = workStatsSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
export const createUserStatsSchema = userStatsSchema.omit({
|
|
id: true,
|
|
createdAt: true,
|
|
updatedAt: true,
|
|
});
|
|
|
|
// Update schemas for partial updates
|
|
export const updateUserSchema = createUserSchema.partial();
|
|
export const updateAuthorSchema = createAuthorSchema.partial();
|
|
export const updateWorkSchema = createWorkSchema.partial();
|
|
export const updateTranslationSchema = createTranslationSchema.partial();
|
|
export const updateTagSchema = createTagSchema.partial();
|
|
export const updateBookmarkSchema = createBookmarkSchema.partial();
|
|
export const updateCommentSchema = createCommentSchema.partial();
|
|
export const updateCollectionSchema = createCollectionSchema.partial();
|
|
export const updateTimelineEventSchema = createTimelineEventSchema.partial();
|
|
export const updateBlogPostSchema = createBlogPostSchema.partial();
|
|
export const updateReadingProgressSchema =
|
|
createReadingProgressSchema.partial();
|
|
export const updateAnnotationSchema = createAnnotationSchema.partial();
|
|
|
|
// New update schemas for GraphQL alignment
|
|
export const updateCountrySchema = createCountrySchema.partial();
|
|
export const updateCitySchema = createCitySchema.partial();
|
|
export const updateBookSchema = createBookSchema.partial();
|
|
export const updateCopyrightSchema = createCopyrightSchema.partial();
|
|
export const updateContributionSchema = createContributionSchema.partial();
|
|
export const updateUserProfileSchema = createUserProfileSchema.partial();
|
|
export const updateReadabilityScoreSchema =
|
|
createReadabilityScoreSchema.partial();
|
|
export const updateWritingStyleSchema = createWritingStyleSchema.partial();
|
|
export const updateEmotionSchema = createEmotionSchema.partial();
|
|
export const updateConceptSchema = createConceptSchema.partial();
|
|
export const updateTopicClusterSchema = createTopicClusterSchema.partial();
|
|
export const updateWorkStatsSchema = createWorkStatsSchema.partial();
|
|
export const updateUserStatsSchema = createUserStatsSchema.partial();
|
|
|
|
// TypeScript types inferred from Zod schemas
|
|
export type User = z.infer<typeof userSchema>;
|
|
export type Author = z.infer<typeof authorSchema>;
|
|
export type Work = z.infer<typeof workSchema>;
|
|
export type Translation = z.infer<typeof translationSchema>;
|
|
export type Tag = z.infer<typeof tagSchema>;
|
|
export type Bookmark = z.infer<typeof bookmarkSchema>;
|
|
export type Comment = z.infer<typeof commentSchema>;
|
|
export type Like = z.infer<typeof likeSchema>;
|
|
export type Collection = z.infer<typeof collectionSchema>;
|
|
export type CollectionItem = z.infer<typeof collectionItemSchema>;
|
|
export type TimelineEvent = z.infer<typeof timelineEventSchema>;
|
|
export type BlogPost = z.infer<typeof blogPostSchema>;
|
|
export type ReadingProgress = z.infer<typeof readingProgressSchema>;
|
|
export type Annotation = z.infer<typeof annotationSchema>;
|
|
export type AnalysisResult = z.infer<typeof analysisResultSchema>;
|
|
|
|
// New types for GraphQL alignment
|
|
export type Country = z.infer<typeof countrySchema>;
|
|
export type City = z.infer<typeof citySchema>;
|
|
export type Book = z.infer<typeof bookSchema>;
|
|
export type Copyright = z.infer<typeof copyrightSchema>;
|
|
export type Contribution = z.infer<typeof contributionSchema>;
|
|
export type UserProfile = z.infer<typeof userProfileSchema>;
|
|
export type ReadabilityScore = z.infer<typeof readabilityScoreSchema>;
|
|
export type WritingStyle = z.infer<typeof writingStyleSchema>;
|
|
export type Emotion = z.infer<typeof emotionSchema>;
|
|
export type Concept = z.infer<typeof conceptSchema>;
|
|
export type TopicCluster = z.infer<typeof topicClusterSchema>;
|
|
export type WorkStats = z.infer<typeof workStatsSchema>;
|
|
export type UserStats = z.infer<typeof userStatsSchema>;
|
|
|
|
// Input types
|
|
export type CreateUser = z.infer<typeof createUserSchema>;
|
|
export type CreateAuthor = z.infer<typeof createAuthorSchema>;
|
|
export type CreateWork = z.infer<typeof createWorkSchema>;
|
|
export type CreateTranslation = z.infer<typeof createTranslationSchema>;
|
|
export type CreateTag = z.infer<typeof createTagSchema>;
|
|
export type CreateBookmark = z.infer<typeof createBookmarkSchema>;
|
|
export type CreateComment = z.infer<typeof createCommentSchema>;
|
|
export type CreateLike = z.infer<typeof createLikeSchema>;
|
|
export type CreateCollection = z.infer<typeof createCollectionSchema>;
|
|
export type CreateCollectionItem = z.infer<typeof createCollectionItemSchema>;
|
|
export type CreateTimelineEvent = z.infer<typeof createTimelineEventSchema>;
|
|
export type CreateBlogPost = z.infer<typeof createBlogPostSchema>;
|
|
export type CreateReadingProgress = z.infer<typeof createReadingProgressSchema>;
|
|
export type CreateAnnotation = z.infer<typeof createAnnotationSchema>;
|
|
export type CreateAnalysisResult = z.infer<typeof createAnalysisResultSchema>;
|
|
|
|
// New create types for GraphQL alignment
|
|
export type CreateCountry = z.infer<typeof createCountrySchema>;
|
|
export type CreateCity = z.infer<typeof createCitySchema>;
|
|
export type CreateBook = z.infer<typeof createBookSchema>;
|
|
export type CreateCopyright = z.infer<typeof createCopyrightSchema>;
|
|
export type CreateContribution = z.infer<typeof createContributionSchema>;
|
|
export type CreateUserProfile = z.infer<typeof createUserProfileSchema>;
|
|
export type CreateReadabilityScore = z.infer<
|
|
typeof createReadabilityScoreSchema
|
|
>;
|
|
export type CreateWritingStyle = z.infer<typeof createWritingStyleSchema>;
|
|
export type CreateEmotion = z.infer<typeof createEmotionSchema>;
|
|
export type CreateConcept = z.infer<typeof createConceptSchema>;
|
|
export type CreateTopicCluster = z.infer<typeof createTopicClusterSchema>;
|
|
export type CreateWorkStats = z.infer<typeof createWorkStatsSchema>;
|
|
export type CreateUserStats = z.infer<typeof createUserStatsSchema>;
|
|
|
|
// Update types
|
|
export type UpdateUser = z.infer<typeof updateUserSchema>;
|
|
export type UpdateAuthor = z.infer<typeof updateAuthorSchema>;
|
|
export type UpdateWork = z.infer<typeof updateWorkSchema>;
|
|
export type UpdateTranslation = z.infer<typeof updateTranslationSchema>;
|
|
export type UpdateTag = z.infer<typeof updateTagSchema>;
|
|
export type UpdateBookmark = z.infer<typeof updateBookmarkSchema>;
|
|
export type UpdateComment = z.infer<typeof updateCommentSchema>;
|
|
export type UpdateCollection = z.infer<typeof updateCollectionSchema>;
|
|
export type UpdateTimelineEvent = z.infer<typeof updateTimelineEventSchema>;
|
|
export type UpdateBlogPost = z.infer<typeof updateBlogPostSchema>;
|
|
export type UpdateReadingProgress = z.infer<typeof updateReadingProgressSchema>;
|
|
export type UpdateAnnotation = z.infer<typeof updateAnnotationSchema>;
|
|
|
|
// New update types for GraphQL alignment
|
|
export type UpdateCountry = z.infer<typeof updateCountrySchema>;
|
|
export type UpdateCity = z.infer<typeof updateCitySchema>;
|
|
export type UpdateBook = z.infer<typeof updateBookSchema>;
|
|
export type UpdateCopyright = z.infer<typeof updateCopyrightSchema>;
|
|
export type UpdateContribution = z.infer<typeof updateContributionSchema>;
|
|
export type UpdateUserProfile = z.infer<typeof updateUserProfileSchema>;
|
|
export type UpdateReadabilityScore = z.infer<
|
|
typeof updateReadabilityScoreSchema
|
|
>;
|
|
export type UpdateWritingStyle = z.infer<typeof updateWritingStyleSchema>;
|
|
export type UpdateEmotion = z.infer<typeof updateEmotionSchema>;
|
|
export type UpdateConcept = z.infer<typeof updateConceptSchema>;
|
|
export type UpdateTopicCluster = z.infer<typeof updateTopicClusterSchema>;
|
|
export type UpdateWorkStats = z.infer<typeof updateWorkStatsSchema>;
|
|
export type UpdateUserStats = z.infer<typeof updateUserStatsSchema>;
|
|
|
|
// API Response schemas
|
|
export const apiResponseSchema = z.object({
|
|
success: z.boolean(),
|
|
data: z.unknown().optional(),
|
|
error: z.string().optional(),
|
|
message: z.string().optional(),
|
|
});
|
|
|
|
export const paginatedResponseSchema = z.object({
|
|
data: z.array(z.unknown()),
|
|
pagination: z.object({
|
|
page: z.number(),
|
|
limit: z.number(),
|
|
total: z.number(),
|
|
totalPages: z.number(),
|
|
}),
|
|
});
|
|
|
|
export type ApiResponse = z.infer<typeof apiResponseSchema>;
|
|
export type PaginatedResponse = z.infer<typeof paginatedResponseSchema>;
|