You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

100 lines
3.8 KiB

  1. import type { Card, CardType, Portal } from '@/types';
  2. import { TEXT_LIMITS } from '@/lib/config';
  3. // Re-export per retro-compatibilità con il codice che importa CARD_LIMITS.
  4. export const CARD_LIMITS = TEXT_LIMITS.card;
  5. export const PORTAL_LIMITS = TEXT_LIMITS.portal;
  6. const VALID_CARD_TYPES: readonly CardType[] = [
  7. 'INFO_PAGE',
  8. 'EXTERNAL_LINK',
  9. 'IMAGE_GALLERY',
  10. 'SERVICE_REQUEST',
  11. 'BOOK',
  12. ] as const;
  13. const ALLOWED_URL_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);
  14. export type ValidationError = {
  15. field: string;
  16. message: string;
  17. limit?: number;
  18. actual?: number;
  19. };
  20. export type ValidationResult = {
  21. valid: boolean;
  22. errors: ValidationError[];
  23. };
  24. function strLen(v: unknown): number {
  25. return typeof v === 'string' ? v.length : 0;
  26. }
  27. export function validateCard(card: Partial<Card>): ValidationResult {
  28. const errors: ValidationError[] = [];
  29. if (typeof card.title !== 'string' || card.title.trim().length === 0) {
  30. errors.push({ field: 'title', message: 'Il titolo è obbligatorio' });
  31. } else if (card.title.length > CARD_LIMITS.title) {
  32. errors.push({ field: 'title', message: 'Titolo troppo lungo', limit: CARD_LIMITS.title, actual: card.title.length });
  33. }
  34. if (card.shortDescription !== undefined && typeof card.shortDescription !== 'string') {
  35. errors.push({ field: 'shortDescription', message: 'Tipo non valido' });
  36. } else if (strLen(card.shortDescription) > CARD_LIMITS.shortDescription) {
  37. errors.push({ field: 'shortDescription', message: 'Descrizione breve troppo lunga', limit: CARD_LIMITS.shortDescription, actual: strLen(card.shortDescription) });
  38. }
  39. if (card.fullContent !== undefined && typeof card.fullContent !== 'string') {
  40. errors.push({ field: 'fullContent', message: 'Tipo non valido' });
  41. } else if (strLen(card.fullContent) > CARD_LIMITS.fullContent) {
  42. errors.push({ field: 'fullContent', message: 'Contenuto troppo lungo', limit: CARD_LIMITS.fullContent, actual: strLen(card.fullContent) });
  43. }
  44. if (card.actionUrl !== undefined && card.actionUrl !== '') {
  45. if (typeof card.actionUrl !== 'string') {
  46. errors.push({ field: 'actionUrl', message: 'Tipo non valido' });
  47. } else if (card.actionUrl.length > CARD_LIMITS.actionUrl) {
  48. errors.push({ field: 'actionUrl', message: 'URL troppo lungo', limit: CARD_LIMITS.actionUrl, actual: card.actionUrl.length });
  49. } else {
  50. try {
  51. const parsed = new URL(card.actionUrl);
  52. if (!ALLOWED_URL_SCHEMES.has(parsed.protocol)) {
  53. errors.push({ field: 'actionUrl', message: `Schema URL non ammesso (${parsed.protocol}). Usa http, https, mailto o tel.` });
  54. }
  55. } catch {
  56. errors.push({ field: 'actionUrl', message: 'URL non valido' });
  57. }
  58. }
  59. }
  60. if (card.cardType !== undefined && !VALID_CARD_TYPES.includes(card.cardType as CardType)) {
  61. errors.push({ field: 'cardType', message: `Tipo card non valido: ${String(card.cardType)}` });
  62. }
  63. return { valid: errors.length === 0, errors };
  64. }
  65. export function validatePortal(portal: Partial<Portal>): ValidationResult {
  66. const errors: ValidationError[] = [];
  67. if (portal.title !== undefined) {
  68. if (typeof portal.title !== 'string') {
  69. errors.push({ field: 'title', message: 'Tipo non valido' });
  70. } else if (portal.title.length > PORTAL_LIMITS.title) {
  71. errors.push({ field: 'title', message: 'Titolo portale troppo lungo', limit: PORTAL_LIMITS.title, actual: portal.title.length });
  72. }
  73. }
  74. if (portal.welcomeText !== undefined) {
  75. if (typeof portal.welcomeText !== 'string') {
  76. errors.push({ field: 'welcomeText', message: 'Tipo non valido' });
  77. } else if (portal.welcomeText.length > PORTAL_LIMITS.welcomeText) {
  78. errors.push({ field: 'welcomeText', message: 'Testo di benvenuto troppo lungo', limit: PORTAL_LIMITS.welcomeText, actual: portal.welcomeText.length });
  79. }
  80. }
  81. return { valid: errors.length === 0, errors };
  82. }