|
- import type { Card, CardType, Portal } from '@/types';
- import { TEXT_LIMITS } from '@/lib/config';
-
- // Re-export per retro-compatibilità con il codice che importa CARD_LIMITS.
- export const CARD_LIMITS = TEXT_LIMITS.card;
- export const PORTAL_LIMITS = TEXT_LIMITS.portal;
-
- const VALID_CARD_TYPES: readonly CardType[] = [
- 'INFO_PAGE',
- 'EXTERNAL_LINK',
- 'IMAGE_GALLERY',
- 'SERVICE_REQUEST', // non esposto in admin né effettivamente utilizzato (vedi nota in types/index.ts)
- 'BOOK',
- 'FULLSCREEN_LOCK',
- ] as const;
-
- const ALLOWED_URL_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);
-
- export type ValidationError = {
- field: string;
- message: string;
- limit?: number;
- actual?: number;
- };
-
- export type ValidationResult = {
- valid: boolean;
- errors: ValidationError[];
- };
-
- function strLen(v: unknown): number {
- return typeof v === 'string' ? v.length : 0;
- }
-
- export function validateCard(card: Partial<Card>): ValidationResult {
- const errors: ValidationError[] = [];
-
- if (typeof card.title !== 'string' || card.title.trim().length === 0) {
- errors.push({ field: 'title', message: 'Title is required. Enter a title before saving.' });
- } else if (card.title.length > CARD_LIMITS.title) {
- errors.push({ field: 'title', message: 'Title is too long', limit: CARD_LIMITS.title, actual: card.title.length });
- }
-
- if (card.shortDescription !== undefined && typeof card.shortDescription !== 'string') {
- errors.push({ field: 'shortDescription', message: 'Invalid type (expected text)' });
- } else if (strLen(card.shortDescription) > CARD_LIMITS.shortDescription) {
- errors.push({ field: 'shortDescription', message: 'Short description is too long', limit: CARD_LIMITS.shortDescription, actual: strLen(card.shortDescription) });
- }
-
- if (card.fullContent !== undefined && typeof card.fullContent !== 'string') {
- errors.push({ field: 'fullContent', message: 'Invalid type (expected text)' });
- } else if (strLen(card.fullContent) > CARD_LIMITS.fullContent) {
- errors.push({ field: 'fullContent', message: 'Content is too long', limit: CARD_LIMITS.fullContent, actual: strLen(card.fullContent) });
- }
-
- // Le card External Link richiedono obbligatoriamente l'URL.
- if (card.cardType === 'EXTERNAL_LINK' && (typeof card.actionUrl !== 'string' || card.actionUrl.trim() === '')) {
- errors.push({ field: 'actionUrl', message: 'URL is required for External Link cards. Enter the destination URL before saving.' });
- }
-
- if (card.actionUrl !== undefined && card.actionUrl !== '') {
- if (typeof card.actionUrl !== 'string') {
- errors.push({ field: 'actionUrl', message: 'Invalid type (expected text)' });
- } else if (card.actionUrl.length > CARD_LIMITS.actionUrl) {
- errors.push({ field: 'actionUrl', message: 'URL is too long', limit: CARD_LIMITS.actionUrl, actual: card.actionUrl.length });
- } else {
- try {
- const parsed = new URL(card.actionUrl);
- if (!ALLOWED_URL_SCHEMES.has(parsed.protocol)) {
- errors.push({ field: 'actionUrl', message: `URL scheme not allowed (${parsed.protocol}). Allowed schemes: http, https, mailto, tel.` });
- }
- } catch {
- errors.push({ field: 'actionUrl', message: 'Invalid URL format. Use a complete URL such as https://example.com.' });
- }
- }
- }
-
- if (card.cardType !== undefined && !VALID_CARD_TYPES.includes(card.cardType as CardType)) {
- errors.push({ field: 'cardType', message: `Invalid card type "${String(card.cardType)}". Pick a type from the dropdown.` });
- }
-
- return { valid: errors.length === 0, errors };
- }
-
- export function validatePortal(portal: Partial<Portal>): ValidationResult {
- const errors: ValidationError[] = [];
-
- if (portal.title !== undefined) {
- if (typeof portal.title !== 'string') {
- errors.push({ field: 'title', message: 'Invalid type (expected text)' });
- } else if (portal.title.length > PORTAL_LIMITS.title) {
- errors.push({ field: 'title', message: 'Portal title is too long', limit: PORTAL_LIMITS.title, actual: portal.title.length });
- }
- }
-
- if (portal.welcomeText !== undefined) {
- if (typeof portal.welcomeText !== 'string') {
- errors.push({ field: 'welcomeText', message: 'Invalid type (expected text)' });
- } else if (portal.welcomeText.length > PORTAL_LIMITS.welcomeText) {
- errors.push({ field: 'welcomeText', message: 'Welcome text is too long', limit: PORTAL_LIMITS.welcomeText, actual: portal.welcomeText.length });
- }
- }
-
- return { valid: errors.length === 0, errors };
- }
|