Finish admin page
This commit is contained in:
@@ -20,3 +20,4 @@ export * from './catalog-admin';
|
||||
export * from './commerce';
|
||||
export * from './content';
|
||||
export * from './customers';
|
||||
export * from './taxonomy-admin';
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { LOCALES } from '@sport/types';
|
||||
|
||||
import { anyIdSchema, slugSchema } from './common';
|
||||
import { offsetPageQuerySchema } from './pagination';
|
||||
|
||||
/**
|
||||
* Per-locale copy for a taxonomy row.
|
||||
*
|
||||
* A partial record, like products and content: publishing an English-only
|
||||
* brand is legitimate, and demanding every locale would mean inventing
|
||||
* Vietnamese copy before anything could be saved.
|
||||
*/
|
||||
const translationSchema = z.object({
|
||||
name: z.string().trim().min(1).max(160),
|
||||
slug: slugSchema,
|
||||
description: z.string().trim().max(2000).nullish(),
|
||||
metaTitle: z.string().trim().max(255).nullish(),
|
||||
metaDescription: z.string().trim().max(500).nullish(),
|
||||
});
|
||||
|
||||
const baseSchema = {
|
||||
/** The fallback name, used when a locale has no translation. */
|
||||
name: z.string().trim().min(1).max(160),
|
||||
slug: slugSchema,
|
||||
description: z.string().trim().max(2000).nullish(),
|
||||
isActive: z.boolean().default(true),
|
||||
metaTitle: z.string().trim().max(255).nullish(),
|
||||
metaDescription: z.string().trim().max(500).nullish(),
|
||||
translations: z.partialRecord(z.enum(LOCALES), translationSchema).default({}),
|
||||
};
|
||||
|
||||
export const brandInputSchema = z.object({
|
||||
...baseSchema,
|
||||
logoId: anyIdSchema.nullish(),
|
||||
});
|
||||
|
||||
export const categoryInputSchema = z.object({
|
||||
...baseSchema,
|
||||
/**
|
||||
* Null means a root category. The service rejects a parent that is the
|
||||
* category itself or one of its own descendants — that would detach the
|
||||
* subtree from the tree and orphan every product under it.
|
||||
*/
|
||||
parentId: anyIdSchema.nullish(),
|
||||
position: z.int().min(0).max(9999).default(0),
|
||||
imageId: anyIdSchema.nullish(),
|
||||
});
|
||||
|
||||
export const collectionInputSchema = z
|
||||
.object({
|
||||
...baseSchema,
|
||||
type: z.enum(['MANUAL', 'AUTOMATED']).default('MANUAL'),
|
||||
bannerId: anyIdSchema.nullish(),
|
||||
startsAt: z.iso.datetime().nullish(),
|
||||
endsAt: z.iso.datetime().nullish(),
|
||||
position: z.int().min(0).max(9999).default(0),
|
||||
})
|
||||
.refine(
|
||||
(value) =>
|
||||
!value.startsAt || !value.endsAt || new Date(value.startsAt) < new Date(value.endsAt),
|
||||
{ message: 'The end date must be after the start date', path: ['endsAt'] },
|
||||
);
|
||||
|
||||
export const taxonomyListQuerySchema = offsetPageQuerySchema.extend({
|
||||
q: z.string().trim().max(120).optional(),
|
||||
/** Admin default is "everything"; the storefront only ever sees active rows. */
|
||||
activeOnly: z.coerce.boolean().optional(),
|
||||
});
|
||||
|
||||
export type BrandInput = z.output<typeof brandInputSchema>;
|
||||
export type CategoryInput = z.output<typeof categoryInputSchema>;
|
||||
export type CollectionInput = z.output<typeof collectionInputSchema>;
|
||||
export type TaxonomyListQuery = z.output<typeof taxonomyListQuerySchema>;
|
||||
Reference in New Issue
Block a user