@imansi/templates 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +557 -0
  3. package/package.json +35 -0
  4. package/src/auth/ForgotPasswordPage.jsx +176 -0
  5. package/src/auth/LoginPage.jsx +265 -0
  6. package/src/auth/RegisterPage.jsx +302 -0
  7. package/src/auth/ResetPasswordPage.jsx +158 -0
  8. package/src/auth/Verify2FAPage.jsx +175 -0
  9. package/src/dashboard/BillingPage.jsx +345 -0
  10. package/src/dashboard/DashboardHome.jsx +246 -0
  11. package/src/dashboard/NotificationsPage.jsx +230 -0
  12. package/src/dashboard/ProfilePage.jsx +272 -0
  13. package/src/dashboard/SettingsPage.jsx +415 -0
  14. package/src/dashboard/UsersTablePage.jsx +317 -0
  15. package/src/extra/CareersPage.jsx +166 -0
  16. package/src/extra/ChangelogPage.jsx +127 -0
  17. package/src/extra/CheckoutPage.jsx +383 -0
  18. package/src/extra/ComingSoonPage.jsx +147 -0
  19. package/src/extra/ErrorPage.jsx +91 -0
  20. package/src/extra/InvoicePage.jsx +241 -0
  21. package/src/extra/LegalPage.jsx +115 -0
  22. package/src/extra/MaintenancePage.jsx +172 -0
  23. package/src/extra/OnboardingPage.jsx +197 -0
  24. package/src/extra/StatusPage.jsx +181 -0
  25. package/src/index.js +53 -0
  26. package/src/layouts/AuthLayout.jsx +104 -0
  27. package/src/layouts/DashboardLayout.jsx +249 -0
  28. package/src/layouts/MarketingLayout.jsx +184 -0
  29. package/src/marketing/AboutPage.jsx +189 -0
  30. package/src/marketing/BlogPage.jsx +182 -0
  31. package/src/marketing/BlogPostPage.jsx +192 -0
  32. package/src/marketing/ContactPage.jsx +546 -0
  33. package/src/marketing/DocsPage.jsx +256 -0
  34. package/src/marketing/HomePage.jsx +702 -0
  35. package/src/marketing/LandingPage.jsx +755 -0
  36. package/src/marketing/PricingPage.jsx +205 -0
@@ -0,0 +1,241 @@
1
+ import { Badge, Button, Card, CardContent, Separator, cn } from '@imansi/ui';
2
+
3
+ export function InvoicePage({
4
+ brandName = 'Imansi',
5
+ brandLogo,
6
+ brandAddress = '',
7
+ brandEmail = '',
8
+ brandPhone = '',
9
+
10
+ invoiceNumber = 'INV-0001',
11
+ invoiceDate = '',
12
+ dueDate = '',
13
+ status = 'paid',
14
+ statusMap = {
15
+ paid: { label: 'Pagada', variant: 'success' },
16
+ pending: { label: 'Pendiente', variant: 'warning' },
17
+ overdue: { label: 'Vencida', variant: 'destructive' },
18
+ },
19
+
20
+ customer = {},
21
+ // { name, email, address, taxId }
22
+
23
+ items = [],
24
+ // [{ description, quantity, rate, amount }]
25
+
26
+ subtotal = '',
27
+ tax = '',
28
+ discount = '',
29
+ total = '',
30
+
31
+ notes = '',
32
+ termsTitle = 'Términos y condiciones',
33
+ terms = '',
34
+ onDownload,
35
+ onPrint,
36
+ className,
37
+ }) {
38
+ const statusInfo = statusMap[status] || statusMap.pending;
39
+
40
+ return (
41
+ <div className={cn('min-h-dvh bg-muted/30 p-4 sm:p-8', className)}>
42
+ <div className="max-w-4xl mx-auto space-y-4">
43
+ {/* Acciones */}
44
+ <div className="flex flex-wrap justify-end gap-2 print:hidden">
45
+ {onDownload && (
46
+ <Button variant="outline" size="sm" onClick={onDownload}>
47
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
48
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
49
+ <polyline points="7 10 12 15 17 10" />
50
+ <line x1="12" y1="15" x2="12" y2="3" />
51
+ </svg>
52
+ Descargar PDF
53
+ </Button>
54
+ )}
55
+ {onPrint && (
56
+ <Button variant="outline" size="sm" onClick={onPrint}>
57
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
58
+ <polyline points="6 9 6 2 18 2 18 9" />
59
+ <path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" />
60
+ <rect x="6" y="14" width="12" height="8" />
61
+ </svg>
62
+ Imprimir
63
+ </Button>
64
+ )}
65
+ </div>
66
+
67
+ {/* Documento */}
68
+ <Card className="shadow-lg print:shadow-none print:border-0">
69
+ <CardContent className="p-8 sm:p-12">
70
+ {/* Header */}
71
+ <div className="flex flex-wrap items-start justify-between gap-6 pb-8">
72
+ <div className="space-y-3">
73
+ <div className="flex items-center gap-2.5">
74
+ {brandLogo || (
75
+ <div className="h-10 w-10 rounded-lg bg-primary text-primary-foreground flex items-center justify-center font-bold">
76
+ {brandName.charAt(0)}
77
+ </div>
78
+ )}
79
+ <span className="text-h4 font-bold">{brandName}</span>
80
+ </div>
81
+ {(brandAddress || brandEmail || brandPhone) && (
82
+ <div className="text-caption text-muted-foreground space-y-0.5">
83
+ {brandAddress && <p>{brandAddress}</p>}
84
+ {brandEmail && <p>{brandEmail}</p>}
85
+ {brandPhone && <p>{brandPhone}</p>}
86
+ </div>
87
+ )}
88
+ </div>
89
+
90
+ <div className="text-right space-y-2">
91
+ <h1 className="text-h2 font-bold tracking-tight">FACTURA</h1>
92
+ <div className="space-y-1">
93
+ <p className="text-caption text-muted-foreground">
94
+ Nº <span className="font-mono font-medium text-foreground">{invoiceNumber}</span>
95
+ </p>
96
+ <div className="flex justify-end">
97
+ <Badge variant={statusInfo.variant}>{statusInfo.label}</Badge>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+
103
+ <Separator />
104
+
105
+ {/* Info de cliente + fechas */}
106
+ <div className="grid gap-8 sm:grid-cols-2 py-8">
107
+ <div className="space-y-3">
108
+ <p className="text-caption uppercase tracking-widest font-semibold text-muted-foreground">
109
+ Facturar a
110
+ </p>
111
+ <div className="space-y-1">
112
+ {customer.name && (
113
+ <p className="text-small font-semibold">{customer.name}</p>
114
+ )}
115
+ {customer.email && (
116
+ <p className="text-small text-muted-foreground">{customer.email}</p>
117
+ )}
118
+ {customer.address && (
119
+ <p className="text-small text-muted-foreground whitespace-pre-line">
120
+ {customer.address}
121
+ </p>
122
+ )}
123
+ {customer.taxId && (
124
+ <p className="text-caption text-muted-foreground pt-1">
125
+ ID Fiscal: <span className="font-mono">{customer.taxId}</span>
126
+ </p>
127
+ )}
128
+ </div>
129
+ </div>
130
+
131
+ <div className="space-y-3 sm:text-right">
132
+ <p className="text-caption uppercase tracking-widest font-semibold text-muted-foreground">
133
+ Detalles
134
+ </p>
135
+ <div className="space-y-1.5">
136
+ <div className="flex sm:justify-end gap-3 text-small">
137
+ <span className="text-muted-foreground">Fecha de emisión:</span>
138
+ <span className="font-medium">{invoiceDate}</span>
139
+ </div>
140
+ {dueDate && (
141
+ <div className="flex sm:justify-end gap-3 text-small">
142
+ <span className="text-muted-foreground">Vencimiento:</span>
143
+ <span className="font-medium">{dueDate}</span>
144
+ </div>
145
+ )}
146
+ </div>
147
+ </div>
148
+ </div>
149
+
150
+ <Separator />
151
+
152
+ {/* Tabla de items */}
153
+ <div className="py-8 overflow-x-auto">
154
+ <table className="w-full text-small">
155
+ <thead>
156
+ <tr className="border-b border-border">
157
+ <th className="text-left py-3 font-semibold">Descripción</th>
158
+ <th className="text-right py-3 font-semibold w-20">Cant.</th>
159
+ <th className="text-right py-3 font-semibold w-28">Precio</th>
160
+ <th className="text-right py-3 font-semibold w-28">Importe</th>
161
+ </tr>
162
+ </thead>
163
+ <tbody>
164
+ {items.map((item, i) => (
165
+ <tr key={i} className="border-b border-border last:border-0">
166
+ <td className="py-3 text-foreground">{item.description}</td>
167
+ <td className="py-3 text-right text-muted-foreground">{item.quantity}</td>
168
+ <td className="py-3 text-right text-muted-foreground">{item.rate}</td>
169
+ <td className="py-3 text-right font-medium">{item.amount}</td>
170
+ </tr>
171
+ ))}
172
+ </tbody>
173
+ </table>
174
+ </div>
175
+
176
+ <Separator />
177
+
178
+ {/* Totales */}
179
+ <div className="py-8 flex justify-end">
180
+ <div className="w-full sm:w-72 space-y-2 text-small">
181
+ <div className="flex justify-between">
182
+ <span className="text-muted-foreground">Subtotal</span>
183
+ <span className="font-medium">{subtotal}</span>
184
+ </div>
185
+ {discount && (
186
+ <div className="flex justify-between text-success">
187
+ <span>Descuento</span>
188
+ <span className="font-medium">-{discount}</span>
189
+ </div>
190
+ )}
191
+ <div className="flex justify-between">
192
+ <span className="text-muted-foreground">Impuestos</span>
193
+ <span className="font-medium">{tax}</span>
194
+ </div>
195
+ <Separator />
196
+ <div className="flex justify-between pt-1">
197
+ <span className="font-semibold">Total</span>
198
+ <span className="text-h4 font-bold">{total}</span>
199
+ </div>
200
+ </div>
201
+ </div>
202
+
203
+ {/* Notas y términos */}
204
+ {(notes || terms) && (
205
+ <>
206
+ <Separator />
207
+ <div className="pt-8 grid gap-8 sm:grid-cols-2">
208
+ {notes && (
209
+ <div className="space-y-2">
210
+ <p className="text-caption uppercase tracking-widest font-semibold text-muted-foreground">
211
+ Notas
212
+ </p>
213
+ <p className="text-small text-muted-foreground leading-relaxed whitespace-pre-line">
214
+ {notes}
215
+ </p>
216
+ </div>
217
+ )}
218
+ {terms && (
219
+ <div className="space-y-2">
220
+ <p className="text-caption uppercase tracking-widest font-semibold text-muted-foreground">
221
+ {termsTitle}
222
+ </p>
223
+ <p className="text-small text-muted-foreground leading-relaxed whitespace-pre-line">
224
+ {terms}
225
+ </p>
226
+ </div>
227
+ )}
228
+ </div>
229
+ </>
230
+ )}
231
+
232
+ {/* Footer */}
233
+ <div className="pt-10 text-center text-caption text-muted-foreground">
234
+ Gracias por tu compra · {brandName}
235
+ </div>
236
+ </CardContent>
237
+ </Card>
238
+ </div>
239
+ </div>
240
+ );
241
+ }
@@ -0,0 +1,115 @@
1
+ import { Link } from 'react-router-dom';
2
+ import { ScrollArea, cn } from '@imansi/ui';
3
+ import { MarketingLayout } from '../layouts/MarketingLayout.jsx';
4
+
5
+ export function LegalPage({
6
+ brandName = 'Imansi',
7
+ brandLogo,
8
+ navLinks = [],
9
+ headerCTA,
10
+ headerSecondaryCTA,
11
+ footerColumns = [],
12
+
13
+ title = 'Términos y Condiciones',
14
+ lastUpdated = 'Última actualización: 12 de septiembre, 2026',
15
+ subtitle = '',
16
+
17
+ tocTitle = 'Contenido',
18
+ sections = [],
19
+ // [{ id, title, content: string | JSX }]
20
+
21
+ contactTitle = '¿Preguntas?',
22
+ contactDescription = 'Si tenés dudas sobre estos términos, escribinos.',
23
+ contactEmail = 'legal@imansi.com',
24
+
25
+ children,
26
+ }) {
27
+ return (
28
+ <MarketingLayout
29
+ brandName={brandName}
30
+ brandLogo={brandLogo}
31
+ navLinks={navLinks}
32
+ headerCTA={headerCTA}
33
+ headerSecondaryCTA={headerSecondaryCTA}
34
+ footerColumns={footerColumns}
35
+ >
36
+ {/* Hero */}
37
+ <section className="imansi-container pt-16 pb-10 border-b border-border">
38
+ <div className="max-w-3xl mx-auto space-y-3">
39
+ <h1 className="text-h1 font-bold tracking-tight">{title}</h1>
40
+ <p className="text-caption text-muted-foreground uppercase tracking-wider">
41
+ {lastUpdated}
42
+ </p>
43
+ {subtitle && (
44
+ <p className="text-body text-muted-foreground leading-relaxed pt-2">
45
+ {subtitle}
46
+ </p>
47
+ )}
48
+ </div>
49
+ </section>
50
+
51
+ {/* Contenido */}
52
+ <section className="imansi-container py-12">
53
+ <div className="grid gap-12 lg:grid-cols-[240px_1fr] max-w-5xl mx-auto">
54
+ {/* TOC */}
55
+ <aside className="hidden lg:block">
56
+ <div className="sticky top-24">
57
+ <p className="text-caption uppercase tracking-wider font-semibold text-muted-foreground mb-3">
58
+ {tocTitle}
59
+ </p>
60
+ <nav className="border-l border-border">
61
+ {sections.map((section) => (
62
+ <a
63
+ key={section.id}
64
+ href={`#${section.id}`}
65
+ className="block pl-3 py-1.5 text-small text-muted-foreground hover:text-foreground transition-colors border-l-2 border-transparent hover:border-primary -ml-px"
66
+ >
67
+ {section.title}
68
+ </a>
69
+ ))}
70
+ </nav>
71
+ </div>
72
+ </aside>
73
+
74
+ {/* Documento */}
75
+ <div className="min-w-0 space-y-10">
76
+ {sections.map((section) => (
77
+ <article key={section.id} id={section.id} className="scroll-mt-24 space-y-4">
78
+ <h2 className="text-h2 font-bold tracking-tight">
79
+ {section.title}
80
+ </h2>
81
+ <div className="text-body text-muted-foreground leading-relaxed space-y-4">
82
+ {typeof section.content === 'string' ? (
83
+ section.content.split('\n\n').map((paragraph, i) => (
84
+ <p key={i}>{paragraph}</p>
85
+ ))
86
+ ) : (
87
+ section.content
88
+ )}
89
+ </div>
90
+ </article>
91
+ ))}
92
+
93
+ {children}
94
+
95
+ {/* Contacto */}
96
+ {contactTitle && (
97
+ <div className="rounded-lg border border-border bg-card p-6 space-y-3 mt-12">
98
+ <h3 className="text-h4 font-semibold">{contactTitle}</h3>
99
+ <p className="text-small text-muted-foreground">
100
+ {contactDescription}
101
+ </p>
102
+ <a
103
+ href={`mailto:${contactEmail}`}
104
+ className="inline-flex text-small font-medium text-primary hover:underline underline-offset-4"
105
+ >
106
+ {contactEmail}
107
+ </a>
108
+ </div>
109
+ )}
110
+ </div>
111
+ </div>
112
+ </section>
113
+ </MarketingLayout>
114
+ );
115
+ }
@@ -0,0 +1,172 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { Button, Separator, cn } from '@imansi/ui';
3
+
4
+ function useCountdown(targetDate) {
5
+ const [timeLeft, setTimeLeft] = useState(() => calculate(targetDate));
6
+
7
+ useEffect(() => {
8
+ const interval = setInterval(() => {
9
+ setTimeLeft(calculate(targetDate));
10
+ }, 1000);
11
+ return () => clearInterval(interval);
12
+ }, [targetDate]);
13
+
14
+ return timeLeft;
15
+ }
16
+
17
+ function calculate(target) {
18
+ const diff = new Date(target).getTime() - Date.now();
19
+ if (diff <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0 };
20
+ return {
21
+ days: Math.floor(diff / (1000 * 60 * 60 * 24)),
22
+ hours: Math.floor((diff / (1000 * 60 * 60)) % 24),
23
+ minutes: Math.floor((diff / (1000 * 60)) % 60),
24
+ seconds: Math.floor((diff / 1000) % 60),
25
+ };
26
+ }
27
+
28
+ export function MaintenancePage({
29
+ brandName = 'Imansi',
30
+ brandLogo,
31
+ badge = 'Mantenimiento',
32
+ title = 'Volvemos en breve',
33
+ subtitle = 'Estamos haciendo mejoras para ofrecerte una mejor experiencia. Gracias por tu paciencia.',
34
+ targetDate,
35
+ showCountdown = true,
36
+ statusItems = [],
37
+ contactEmail = 'soporte@imansi.com',
38
+ footerNote,
39
+ className,
40
+ }) {
41
+ const countdown = useCountdown(targetDate || Date.now() + 1000 * 60 * 60 * 24);
42
+
43
+ const timeBlocks = [
44
+ { label: 'Días', value: countdown.days },
45
+ { label: 'Horas', value: countdown.hours },
46
+ { label: 'Minutos', value: countdown.minutes },
47
+ { label: 'Segundos', value: countdown.seconds },
48
+ ];
49
+
50
+ return (
51
+ <div className={cn('min-h-dvh flex flex-col bg-background text-foreground relative overflow-hidden', className)}>
52
+ {/* Fondo con stripes diagonales */}
53
+ <div
54
+ className="absolute inset-0 opacity-[0.03] pointer-events-none"
55
+ style={{
56
+ backgroundImage: `repeating-linear-gradient(45deg, currentColor 0, currentColor 1px, transparent 1px, transparent 20px)`,
57
+ }}
58
+ aria-hidden="true"
59
+ />
60
+
61
+ {/* Header */}
62
+ <header className="relative imansi-container py-6">
63
+ <div className="flex items-center justify-center gap-2.5">
64
+ {brandLogo || (
65
+ <div className="h-10 w-10 rounded-lg bg-primary text-primary-foreground flex items-center justify-center font-bold">
66
+ {brandName.charAt(0)}
67
+ </div>
68
+ )}
69
+ <span className="text-h4 font-semibold tracking-tight">{brandName}</span>
70
+ </div>
71
+ </header>
72
+
73
+ {/* Contenido */}
74
+ <main className="relative flex-1 flex items-center justify-center p-6">
75
+ <div className="max-w-2xl w-full text-center space-y-10">
76
+ {/* Icono + badge */}
77
+ <div className="space-y-6">
78
+ <div className="inline-flex h-20 w-20 items-center justify-center rounded-full bg-warning/10 text-warning">
79
+ <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
80
+ <circle cx="12" cy="12" r="3" />
81
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
82
+ </svg>
83
+ </div>
84
+
85
+ <span className="inline-flex items-center rounded-full border border-border bg-card px-4 py-1.5 text-caption font-medium uppercase tracking-widest text-muted-foreground">
86
+ {badge}
87
+ </span>
88
+ </div>
89
+
90
+ {/* Texto */}
91
+ <div className="space-y-4">
92
+ <h1 className="text-display font-bold tracking-tight leading-[1.05]">
93
+ {title}
94
+ </h1>
95
+ <p className="text-body text-muted-foreground leading-relaxed max-w-lg mx-auto">
96
+ {subtitle}
97
+ </p>
98
+ </div>
99
+
100
+ {/* Countdown */}
101
+ {showCountdown && targetDate && (
102
+ <div className="pt-2">
103
+ <div className="grid grid-cols-4 gap-3 max-w-lg mx-auto">
104
+ {timeBlocks.map((block) => (
105
+ <div
106
+ key={block.label}
107
+ className="rounded-lg border border-border bg-card p-4 text-center"
108
+ >
109
+ <p className="text-h1 font-bold tracking-tight tabular-nums">
110
+ {String(block.value).padStart(2, '0')}
111
+ </p>
112
+ <p className="text-caption uppercase tracking-wider text-muted-foreground mt-1">
113
+ {block.label}
114
+ </p>
115
+ </div>
116
+ ))}
117
+ </div>
118
+ </div>
119
+ )}
120
+
121
+ {/* Status items */}
122
+ {statusItems.length > 0 && (
123
+ <div className="rounded-lg border border-border bg-card p-5 max-w-lg mx-auto text-left space-y-3">
124
+ <p className="text-caption uppercase tracking-wider font-semibold text-muted-foreground">
125
+ Estado del servicio
126
+ </p>
127
+ <Separator />
128
+ <ul className="space-y-2.5">
129
+ {statusItems.map((item, i) => (
130
+ <li key={i} className="flex items-center justify-between gap-3 text-small">
131
+ <span className="flex items-center gap-2">
132
+ <span
133
+ className={cn(
134
+ 'h-2 w-2 rounded-full',
135
+ item.status === 'ok' && 'bg-success',
136
+ item.status === 'warning' && 'bg-warning',
137
+ item.status === 'down' && 'bg-destructive'
138
+ )}
139
+ />
140
+ {item.label}
141
+ </span>
142
+ <span className="text-caption text-muted-foreground">
143
+ {item.message}
144
+ </span>
145
+ </li>
146
+ ))}
147
+ </ul>
148
+ </div>
149
+ )}
150
+
151
+ {/* Contact */}
152
+ {contactEmail && (
153
+ <p className="text-small text-muted-foreground">
154
+ ¿Necesitás ayuda urgente? Escribinos a{' '}
155
+ <a
156
+ href={`mailto:${contactEmail}`}
157
+ className="text-primary hover:underline underline-offset-4 font-medium"
158
+ >
159
+ {contactEmail}
160
+ </a>
161
+ </p>
162
+ )}
163
+ </div>
164
+ </main>
165
+
166
+ {/* Footer */}
167
+ <footer className="relative imansi-container py-6 text-center text-caption text-muted-foreground">
168
+ {footerNote || `© ${new Date().getFullYear()} ${brandName}`}
169
+ </footer>
170
+ </div>
171
+ );
172
+ }