@cimplify/sdk 0.40.1 → 0.41.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 (219) hide show
  1. package/dist/dispatcher.mjs +3 -2
  2. package/dist/styles.css +1 -1
  3. package/package.json +1 -1
  4. package/templates/storefront-bakery/.env.example +5 -0
  5. package/templates/storefront-bakery/AGENTS.md +57 -0
  6. package/templates/storefront-bakery/app/about/page.tsx +21 -44
  7. package/templates/storefront-bakery/app/categories/[slug]/page.tsx +2 -1
  8. package/templates/storefront-bakery/app/collections/[slug]/page.tsx +2 -1
  9. package/templates/storefront-bakery/app/error.tsx +60 -0
  10. package/templates/storefront-bakery/app/faq/page.tsx +13 -89
  11. package/templates/storefront-bakery/app/layout.tsx +37 -2
  12. package/templates/storefront-bakery/app/llms.txt/route.ts +94 -0
  13. package/templates/storefront-bakery/app/not-found.tsx +39 -0
  14. package/templates/storefront-bakery/app/page.tsx +6 -6
  15. package/templates/storefront-bakery/app/privacy/page.tsx +24 -68
  16. package/templates/storefront-bakery/app/robots.ts +18 -0
  17. package/templates/storefront-bakery/app/shop/page.tsx +3 -2
  18. package/templates/storefront-bakery/app/sitemap.ts +62 -0
  19. package/templates/storefront-bakery/app/terms/page.tsx +24 -82
  20. package/templates/storefront-bakery/components/footer.tsx +88 -130
  21. package/templates/storefront-bakery/components/header.tsx +8 -16
  22. package/templates/storefront-bakery/lib/brand.ts +453 -0
  23. package/templates/storefront-fashion/.env.example +16 -0
  24. package/templates/storefront-fashion/AGENTS.md +52 -0
  25. package/templates/storefront-fashion/README.md +77 -0
  26. package/templates/storefront-fashion/app/about/page.tsx +41 -0
  27. package/templates/storefront-fashion/app/cart/page.tsx +9 -0
  28. package/templates/storefront-fashion/app/categories/[slug]/listing-client.tsx +19 -0
  29. package/templates/storefront-fashion/app/categories/[slug]/page.tsx +130 -0
  30. package/templates/storefront-fashion/app/checkout/page.tsx +17 -0
  31. package/templates/storefront-fashion/app/collections/[slug]/listing-client.tsx +20 -0
  32. package/templates/storefront-fashion/app/collections/[slug]/page.tsx +130 -0
  33. package/templates/storefront-fashion/app/error.tsx +61 -0
  34. package/templates/storefront-fashion/app/faq/page.tsx +46 -0
  35. package/templates/storefront-fashion/app/globals.css +46 -0
  36. package/templates/storefront-fashion/app/layout.tsx +76 -0
  37. package/templates/storefront-fashion/app/llms.txt/route.ts +94 -0
  38. package/templates/storefront-fashion/app/not-found.tsx +39 -0
  39. package/templates/storefront-fashion/app/orders/[id]/page.tsx +24 -0
  40. package/templates/storefront-fashion/app/page.tsx +183 -0
  41. package/templates/storefront-fashion/app/privacy/page.tsx +44 -0
  42. package/templates/storefront-fashion/app/products/[slug]/page.tsx +165 -0
  43. package/templates/storefront-fashion/app/products/[slug]/product-detail.tsx +71 -0
  44. package/templates/storefront-fashion/app/robots.ts +18 -0
  45. package/templates/storefront-fashion/app/shop/page.tsx +63 -0
  46. package/templates/storefront-fashion/app/shop/shop-client.tsx +32 -0
  47. package/templates/storefront-fashion/app/sitemap.ts +59 -0
  48. package/templates/storefront-fashion/app/terms/page.tsx +44 -0
  49. package/templates/storefront-fashion/components/brand-marquee.tsx +27 -0
  50. package/templates/storefront-fashion/components/cart-pill.tsx +32 -0
  51. package/templates/storefront-fashion/components/category-grid.tsx +28 -0
  52. package/templates/storefront-fashion/components/category-tiles.tsx +104 -0
  53. package/templates/storefront-fashion/components/collection-strip.tsx +45 -0
  54. package/templates/storefront-fashion/components/feature-hero.tsx +82 -0
  55. package/templates/storefront-fashion/components/footer.tsx +153 -0
  56. package/templates/storefront-fashion/components/header.tsx +43 -0
  57. package/templates/storefront-fashion/components/hero.tsx +28 -0
  58. package/templates/storefront-fashion/components/nav-link.tsx +20 -0
  59. package/templates/storefront-fashion/components/newsletter.tsx +50 -0
  60. package/templates/storefront-fashion/components/promo-banner.tsx +41 -0
  61. package/templates/storefront-fashion/components/providers.tsx +31 -0
  62. package/templates/storefront-fashion/components/section-heading.tsx +37 -0
  63. package/templates/storefront-fashion/components/store-product-card.tsx +83 -0
  64. package/templates/storefront-fashion/components/trade-in-cta.tsx +54 -0
  65. package/templates/storefront-fashion/components/trust-bar.tsx +66 -0
  66. package/templates/storefront-fashion/lib/brand.ts +421 -0
  67. package/templates/storefront-fashion/lib/cart.ts +27 -0
  68. package/templates/storefront-fashion/next.config.ts +40 -0
  69. package/templates/storefront-fashion/package.json +28 -0
  70. package/templates/storefront-fashion/postcss.config.mjs +7 -0
  71. package/templates/storefront-fashion/tsconfig.json +23 -0
  72. package/templates/storefront-grocery/.env.example +16 -0
  73. package/templates/storefront-grocery/AGENTS.md +39 -0
  74. package/templates/storefront-grocery/README.md +73 -0
  75. package/templates/storefront-grocery/app/about/page.tsx +38 -0
  76. package/templates/storefront-grocery/app/cart/page.tsx +9 -0
  77. package/templates/storefront-grocery/app/categories/[slug]/listing-client.tsx +19 -0
  78. package/templates/storefront-grocery/app/categories/[slug]/page.tsx +118 -0
  79. package/templates/storefront-grocery/app/checkout/page.tsx +17 -0
  80. package/templates/storefront-grocery/app/collections/[slug]/listing-client.tsx +20 -0
  81. package/templates/storefront-grocery/app/collections/[slug]/page.tsx +118 -0
  82. package/templates/storefront-grocery/app/error.tsx +60 -0
  83. package/templates/storefront-grocery/app/faq/page.tsx +46 -0
  84. package/templates/storefront-grocery/app/globals.css +45 -0
  85. package/templates/storefront-grocery/app/layout.tsx +75 -0
  86. package/templates/storefront-grocery/app/llms.txt/route.ts +94 -0
  87. package/templates/storefront-grocery/app/not-found.tsx +39 -0
  88. package/templates/storefront-grocery/app/orders/[id]/page.tsx +21 -0
  89. package/templates/storefront-grocery/app/page.tsx +97 -0
  90. package/templates/storefront-grocery/app/privacy/page.tsx +44 -0
  91. package/templates/storefront-grocery/app/robots.ts +18 -0
  92. package/templates/storefront-grocery/app/shop/page.tsx +31 -0
  93. package/templates/storefront-grocery/app/shop/shop-client.tsx +27 -0
  94. package/templates/storefront-grocery/app/sitemap.ts +62 -0
  95. package/templates/storefront-grocery/app/terms/page.tsx +44 -0
  96. package/templates/storefront-grocery/components/cart-pill.tsx +32 -0
  97. package/templates/storefront-grocery/components/category-grid.tsx +28 -0
  98. package/templates/storefront-grocery/components/collection-strip.tsx +45 -0
  99. package/templates/storefront-grocery/components/footer.tsx +148 -0
  100. package/templates/storefront-grocery/components/header.tsx +43 -0
  101. package/templates/storefront-grocery/components/hero.tsx +25 -0
  102. package/templates/storefront-grocery/components/nav-link.tsx +20 -0
  103. package/templates/storefront-grocery/components/providers.tsx +31 -0
  104. package/templates/storefront-grocery/components/store-product-card.tsx +83 -0
  105. package/templates/storefront-grocery/lib/brand.ts +284 -0
  106. package/templates/storefront-grocery/lib/cart.ts +27 -0
  107. package/templates/storefront-grocery/next.config.ts +40 -0
  108. package/templates/storefront-grocery/package.json +28 -0
  109. package/templates/storefront-grocery/postcss.config.mjs +7 -0
  110. package/templates/storefront-grocery/tsconfig.json +23 -0
  111. package/templates/storefront-restaurant/.env.example +16 -0
  112. package/templates/storefront-restaurant/AGENTS.md +39 -0
  113. package/templates/storefront-restaurant/README.md +73 -0
  114. package/templates/storefront-restaurant/app/about/page.tsx +38 -0
  115. package/templates/storefront-restaurant/app/cart/page.tsx +9 -0
  116. package/templates/storefront-restaurant/app/categories/[slug]/listing-client.tsx +19 -0
  117. package/templates/storefront-restaurant/app/categories/[slug]/page.tsx +118 -0
  118. package/templates/storefront-restaurant/app/checkout/page.tsx +17 -0
  119. package/templates/storefront-restaurant/app/collections/[slug]/listing-client.tsx +20 -0
  120. package/templates/storefront-restaurant/app/collections/[slug]/page.tsx +118 -0
  121. package/templates/storefront-restaurant/app/error.tsx +60 -0
  122. package/templates/storefront-restaurant/app/faq/page.tsx +46 -0
  123. package/templates/storefront-restaurant/app/globals.css +44 -0
  124. package/templates/storefront-restaurant/app/layout.tsx +80 -0
  125. package/templates/storefront-restaurant/app/llms.txt/route.ts +94 -0
  126. package/templates/storefront-restaurant/app/not-found.tsx +39 -0
  127. package/templates/storefront-restaurant/app/orders/[id]/page.tsx +21 -0
  128. package/templates/storefront-restaurant/app/page.tsx +97 -0
  129. package/templates/storefront-restaurant/app/privacy/page.tsx +44 -0
  130. package/templates/storefront-restaurant/app/robots.ts +18 -0
  131. package/templates/storefront-restaurant/app/shop/page.tsx +31 -0
  132. package/templates/storefront-restaurant/app/shop/shop-client.tsx +27 -0
  133. package/templates/storefront-restaurant/app/sitemap.ts +62 -0
  134. package/templates/storefront-restaurant/app/terms/page.tsx +44 -0
  135. package/templates/storefront-restaurant/components/cart-pill.tsx +32 -0
  136. package/templates/storefront-restaurant/components/category-grid.tsx +28 -0
  137. package/templates/storefront-restaurant/components/collection-strip.tsx +45 -0
  138. package/templates/storefront-restaurant/components/footer.tsx +148 -0
  139. package/templates/storefront-restaurant/components/header.tsx +43 -0
  140. package/templates/storefront-restaurant/components/hero.tsx +25 -0
  141. package/templates/storefront-restaurant/components/nav-link.tsx +20 -0
  142. package/templates/storefront-restaurant/components/product-modal.tsx +105 -0
  143. package/templates/storefront-restaurant/components/providers.tsx +31 -0
  144. package/templates/storefront-restaurant/components/store-product-card.tsx +83 -0
  145. package/templates/storefront-restaurant/lib/brand.ts +287 -0
  146. package/templates/storefront-restaurant/lib/cart.ts +27 -0
  147. package/templates/storefront-restaurant/next.config.ts +40 -0
  148. package/templates/storefront-restaurant/package.json +28 -0
  149. package/templates/storefront-restaurant/postcss.config.mjs +7 -0
  150. package/templates/storefront-restaurant/tsconfig.json +23 -0
  151. package/templates/storefront-retail/.env.example +5 -0
  152. package/templates/storefront-retail/AGENTS.md +64 -0
  153. package/templates/storefront-retail/app/about/page.tsx +24 -54
  154. package/templates/storefront-retail/app/categories/[slug]/page.tsx +2 -1
  155. package/templates/storefront-retail/app/collections/[slug]/page.tsx +2 -1
  156. package/templates/storefront-retail/app/error.tsx +61 -0
  157. package/templates/storefront-retail/app/faq/page.tsx +11 -92
  158. package/templates/storefront-retail/app/layout.tsx +37 -8
  159. package/templates/storefront-retail/app/llms.txt/route.ts +94 -0
  160. package/templates/storefront-retail/app/not-found.tsx +39 -0
  161. package/templates/storefront-retail/app/page.tsx +16 -73
  162. package/templates/storefront-retail/app/privacy/page.tsx +24 -81
  163. package/templates/storefront-retail/app/products/[slug]/page.tsx +165 -0
  164. package/templates/storefront-retail/app/products/[slug]/product-detail.tsx +71 -0
  165. package/templates/storefront-retail/app/robots.ts +18 -0
  166. package/templates/storefront-retail/app/shop/page.tsx +3 -3
  167. package/templates/storefront-retail/app/sitemap.ts +59 -0
  168. package/templates/storefront-retail/app/terms/page.tsx +24 -97
  169. package/templates/storefront-retail/components/brand-marquee.tsx +6 -15
  170. package/templates/storefront-retail/components/feature-hero.tsx +2 -1
  171. package/templates/storefront-retail/components/footer.tsx +85 -120
  172. package/templates/storefront-retail/components/header.tsx +10 -12
  173. package/templates/storefront-retail/components/newsletter.tsx +7 -9
  174. package/templates/storefront-retail/components/promo-banner.tsx +12 -15
  175. package/templates/storefront-retail/components/store-product-card.tsx +7 -7
  176. package/templates/storefront-retail/components/trade-in-cta.tsx +11 -17
  177. package/templates/storefront-retail/components/trust-bar.tsx +45 -5
  178. package/templates/storefront-retail/lib/brand.ts +567 -0
  179. package/templates/storefront-services/.env.example +16 -0
  180. package/templates/storefront-services/AGENTS.md +41 -0
  181. package/templates/storefront-services/README.md +73 -0
  182. package/templates/storefront-services/app/about/page.tsx +38 -0
  183. package/templates/storefront-services/app/cart/page.tsx +9 -0
  184. package/templates/storefront-services/app/categories/[slug]/listing-client.tsx +19 -0
  185. package/templates/storefront-services/app/categories/[slug]/page.tsx +118 -0
  186. package/templates/storefront-services/app/checkout/page.tsx +17 -0
  187. package/templates/storefront-services/app/collections/[slug]/listing-client.tsx +20 -0
  188. package/templates/storefront-services/app/collections/[slug]/page.tsx +118 -0
  189. package/templates/storefront-services/app/error.tsx +60 -0
  190. package/templates/storefront-services/app/faq/page.tsx +46 -0
  191. package/templates/storefront-services/app/globals.css +45 -0
  192. package/templates/storefront-services/app/layout.tsx +80 -0
  193. package/templates/storefront-services/app/llms.txt/route.ts +94 -0
  194. package/templates/storefront-services/app/not-found.tsx +39 -0
  195. package/templates/storefront-services/app/orders/[id]/page.tsx +21 -0
  196. package/templates/storefront-services/app/page.tsx +97 -0
  197. package/templates/storefront-services/app/privacy/page.tsx +44 -0
  198. package/templates/storefront-services/app/robots.ts +18 -0
  199. package/templates/storefront-services/app/shop/page.tsx +31 -0
  200. package/templates/storefront-services/app/shop/shop-client.tsx +27 -0
  201. package/templates/storefront-services/app/sitemap.ts +62 -0
  202. package/templates/storefront-services/app/terms/page.tsx +44 -0
  203. package/templates/storefront-services/components/cart-pill.tsx +32 -0
  204. package/templates/storefront-services/components/category-grid.tsx +28 -0
  205. package/templates/storefront-services/components/collection-strip.tsx +45 -0
  206. package/templates/storefront-services/components/footer.tsx +148 -0
  207. package/templates/storefront-services/components/header.tsx +43 -0
  208. package/templates/storefront-services/components/hero.tsx +25 -0
  209. package/templates/storefront-services/components/nav-link.tsx +20 -0
  210. package/templates/storefront-services/components/product-modal.tsx +105 -0
  211. package/templates/storefront-services/components/providers.tsx +31 -0
  212. package/templates/storefront-services/components/store-product-card.tsx +83 -0
  213. package/templates/storefront-services/lib/brand.ts +303 -0
  214. package/templates/storefront-services/lib/cart.ts +27 -0
  215. package/templates/storefront-services/next.config.ts +40 -0
  216. package/templates/storefront-services/package.json +28 -0
  217. package/templates/storefront-services/postcss.config.mjs +7 -0
  218. package/templates/storefront-services/tsconfig.json +23 -0
  219. /package/templates/{storefront-retail → storefront-grocery}/components/product-modal.tsx +0 -0
@@ -0,0 +1,61 @@
1
+ "use client";
2
+
3
+ import { useEffect } from "react";
4
+ import Link from "next/link";
5
+
6
+ /**
7
+ * Root error boundary. Next.js calls this whenever a thrown error escapes
8
+ * a Server Component without being caught by a closer `error.tsx`.
9
+ *
10
+ * Wire `reportError` (Sentry, Datadog, etc.) here so production failures
11
+ * surface — silently recovering hides real bugs.
12
+ */
13
+ export default function GlobalError({
14
+ error,
15
+ reset,
16
+ }: {
17
+ error: Error & { digest?: string };
18
+ reset: () => void;
19
+ }) {
20
+ useEffect(() => {
21
+ // TODO: replace with your error reporter
22
+ // eslint-disable-next-line no-console
23
+ console.error("Storefront error:", error);
24
+ }, [error]);
25
+
26
+ return (
27
+ <section className="max-w-2xl mx-auto px-6 sm:px-8 py-20 text-center">
28
+ <p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-3">
29
+ Something broke
30
+ </p>
31
+ <h1 className="text-[clamp(2rem,4vw,3rem)] font-bold mb-4 -tracking-[0.025em]">
32
+ That wasn&apos;t supposed to happen.
33
+ </h1>
34
+ <p className="text-muted-foreground leading-relaxed mb-8">
35
+ We&apos;ve been notified. Refresh the page, or head back home — most
36
+ of the time the second try just works.
37
+ </p>
38
+ {error.digest && (
39
+ <p className="text-xs font-mono text-muted-foreground mb-6">
40
+ Reference:{" "}
41
+ <code className="text-foreground">{error.digest}</code>
42
+ </p>
43
+ )}
44
+ <div className="flex flex-wrap items-center justify-center gap-3">
45
+ <button
46
+ type="button"
47
+ onClick={reset}
48
+ className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md bg-primary text-primary-foreground font-semibold text-sm hover:bg-primary/90 transition-colors"
49
+ >
50
+ Try again
51
+ </button>
52
+ <Link
53
+ href="/"
54
+ className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md border border-border hover:bg-muted transition-colors text-sm font-medium"
55
+ >
56
+ Back home
57
+ </Link>
58
+ </div>
59
+ </section>
60
+ );
61
+ }
@@ -1,106 +1,25 @@
1
1
  import type { Metadata } from "next";
2
+ import { brand } from "@/lib/brand";
2
3
 
3
4
  export const metadata: Metadata = {
4
- title: "Support — Currents Electronics",
5
- description:
6
- "Shipping, warranty, repairs, returns, payment — answers to the questions we hear most often.",
5
+ title: `Support — ${brand.name}`,
6
+ description: "Shipping, warranty, repairs, returns, payment — answers to the questions we hear most often.",
7
7
  };
8
8
 
9
- interface QA {
10
- q: string;
11
- a: string;
12
- }
13
-
14
- const SECTIONS: { title: string; items: QA[] }[] = [
15
- {
16
- title: "Ordering & delivery",
17
- items: [
18
- {
19
- q: "How fast is shipping?",
20
- a: "Free same-day delivery within Greater Accra for orders placed before 4pm. Outside Accra, we use a partner courier — usually 1–3 business days, with tracking sent by SMS.",
21
- },
22
- {
23
- q: "Can I pick up in store?",
24
- a: "Yes. Choose 'Pickup' at checkout and we'll have your order boxed at our Atomic Junction store within 30 minutes. Bring a photo ID matching the order name.",
25
- },
26
- {
27
- q: "Do you ship internationally?",
28
- a: "We ship across West Africa via DHL — rates and ETAs are calculated at checkout once you enter your destination.",
29
- },
30
- {
31
- q: "How do I track my order?",
32
- a: "You'll get an SMS and email with a tracking link within 30 minutes of dispatch. Same-day Accra orders include the rider's phone number.",
33
- },
34
- ],
35
- },
36
- {
37
- title: "Warranty & repairs",
38
- items: [
39
- {
40
- q: "What does the two-year warranty cover?",
41
- a: "Manufacturing defects, electrical failures, and battery degradation below 80% within the first 24 months. Accidental damage, water damage, and software issues caused by user installs are excluded.",
42
- },
43
- {
44
- q: "Where do I send a faulty device?",
45
- a: "Drop it at our Atomic Junction store, or request a free pickup from your address by emailing support@currentselectronics.test. Loaner devices are available for warranty claims while we diagnose.",
46
- },
47
- {
48
- q: "Can you fix devices bought elsewhere?",
49
- a: "We offer paid repairs on Apple and Samsung devices regardless of where they were purchased. Expect a quote within 48 hours of inspection.",
50
- },
51
- ],
52
- },
53
- {
54
- title: "Trade-in & financing",
55
- items: [
56
- {
57
- q: "How does trade-in work?",
58
- a: "Tell us the model and condition of your device, get an instant estimate, and ship it free or drop it at our store. Once we verify, we credit your account or pay out via Mobile Money — your choice.",
59
- },
60
- {
61
- q: "Do you offer instalment payments?",
62
- a: "Yes. Pay in 3 (interest-free) or 6/12 monthly instalments via our partner Fidelity Bank. Available at checkout for orders over GH₵2,000.",
63
- },
64
- {
65
- q: "Are there bulk discounts for businesses?",
66
- a: "Yes. Email business@currentselectronics.test with your shopping list and team size — most orders over 5 units qualify for a discount, plus free on-site setup.",
67
- },
68
- ],
69
- },
70
- {
71
- title: "Payment & returns",
72
- items: [
73
- {
74
- q: "What payment methods do you accept?",
75
- a: "Mobile Money (MTN, Telecel, AirtelTigo), Visa/Mastercard, instalments via Fidelity Bank, and cash on delivery for Accra orders.",
76
- },
77
- {
78
- q: "What's your return policy?",
79
- a: "14 days, no questions asked, on any sealed product. For opened items, returns are accepted within 7 days subject to a 10% restocking fee. We can't accept returns on activated SIM-bundled phones once the SIM is registered.",
80
- },
81
- {
82
- q: "Are products genuine?",
83
- a: "Yes. We're an authorised dealer for every brand we stock. Every product ships with the manufacturer's serial number registered to your name — verify it on the brand's official portal anytime.",
84
- },
85
- ],
86
- },
87
- ];
88
-
89
9
  export default function FaqPage() {
10
+ const f = brand.faq;
90
11
  return (
91
12
  <article className="max-w-3xl mx-auto px-8 py-16">
92
13
  <p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-2">
93
- Support
14
+ {f.eyebrow}
94
15
  </p>
95
16
  <h1 className="text-[clamp(2.25rem,5vw,3.5rem)] font-bold mb-10 -tracking-[0.025em]">
96
- Questions, answered.
17
+ {f.title}
97
18
  </h1>
98
19
  <div className="space-y-12">
99
- {SECTIONS.map((section) => (
20
+ {f.sections.map((section) => (
100
21
  <section key={section.title}>
101
- <h2 className="text-2xl font-semibold mb-5 -tracking-[0.02em]">
102
- {section.title}
103
- </h2>
22
+ <h2 className="text-2xl font-semibold mb-5 -tracking-[0.02em]">{section.title}</h2>
104
23
  <dl className="space-y-6">
105
24
  {section.items.map((item) => (
106
25
  <div key={item.q}>
@@ -113,12 +32,12 @@ export default function FaqPage() {
113
32
  ))}
114
33
  </div>
115
34
  <p className="mt-12 pt-8 border-t border-border text-sm text-muted-foreground">
116
- Still stuck? Email{" "}
35
+ {f.contactPrompt}{" "}
117
36
  <a
118
- href="mailto:support@currentselectronics.test"
37
+ href={`mailto:${f.contactEmail}`}
119
38
  className="text-primary font-semibold hover:underline"
120
39
  >
121
- support@currentselectronics.test
40
+ {f.contactEmail}
122
41
  </a>{" "}
123
42
  and a real human will reply within 24 hours.
124
43
  </p>
@@ -4,8 +4,7 @@ import "./globals.css";
4
4
  import { Providers } from "@/components/providers";
5
5
  import { Header } from "@/components/header";
6
6
  import { Footer } from "@/components/footer";
7
- import { ProductModal } from "@/components/product-modal";
8
- import { Suspense } from "react";
7
+ import { brand } from "@/lib/brand";
9
8
 
10
9
  const inter = Inter({
11
10
  subsets: ["latin"],
@@ -19,10 +18,39 @@ const mono = JetBrains_Mono({
19
18
  display: "swap",
20
19
  });
21
20
 
21
+ const SITE_URL =
22
+ process.env.NEXT_PUBLIC_SITE_URL?.trim() || "https://example.com";
23
+
22
24
  export const metadata: Metadata = {
23
- title: "Currents Electronics",
24
- description:
25
- "The latest laptops, phones, audio, and accessories — curated, in-stock, shipped from Accra to Africa.",
25
+ metadataBase: new URL(SITE_URL),
26
+ title: {
27
+ default: brand.name,
28
+ template: `%s — ${brand.name}`,
29
+ },
30
+ description: brand.description,
31
+ openGraph: {
32
+ type: "website",
33
+ siteName: brand.name,
34
+ locale: brand.locale,
35
+ },
36
+ twitter: { card: "summary_large_image" },
37
+ };
38
+
39
+ const ORGANIZATION_LD = {
40
+ "@context": "https://schema.org",
41
+ "@type": brand.schemaType,
42
+ name: brand.name,
43
+ url: SITE_URL,
44
+ description: brand.description,
45
+ email: brand.contact.email,
46
+ telephone: brand.contact.phoneTel,
47
+ address: {
48
+ "@type": "PostalAddress",
49
+ streetAddress: brand.contact.streetAddress,
50
+ addressLocality: brand.contact.city,
51
+ addressCountry: brand.contact.countryCode,
52
+ },
53
+ sameAs: brand.socials.map((s) => s.href),
26
54
  };
27
55
 
28
56
  export default function RootLayout({ children }: { children: React.ReactNode }) {
@@ -32,13 +60,14 @@ export default function RootLayout({ children }: { children: React.ReactNode })
32
60
  suppressHydrationWarning
33
61
  className="min-h-screen flex flex-col bg-background text-foreground font-sans"
34
62
  >
63
+ <script
64
+ type="application/ld+json"
65
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(ORGANIZATION_LD) }}
66
+ />
35
67
  <Providers>
36
68
  <Header />
37
69
  <main className="flex-1 pb-12 w-full">{children}</main>
38
70
  <Footer />
39
- <Suspense fallback={null}>
40
- <ProductModal />
41
- </Suspense>
42
71
  </Providers>
43
72
  </body>
44
73
  </html>
@@ -0,0 +1,94 @@
1
+ import { cacheTag, cacheLife } from "next/cache";
2
+ import { getServerClient, tags, type Product } from "@cimplify/sdk/server";
3
+ import { brand } from "@/lib/brand";
4
+
5
+ const SITE_URL =
6
+ process.env.NEXT_PUBLIC_SITE_URL?.trim() || "https://example.com";
7
+
8
+ async function buildLlmsTxt(): Promise<string> {
9
+ "use cache";
10
+ cacheTag(tags.products(), tags.categories(), tags.collections());
11
+ cacheLife("hours");
12
+
13
+ const client = getServerClient();
14
+ const [productsRes, categoriesRes, collectionsRes] = await Promise.all([
15
+ client.catalogue.getProducts({ limit: 500 }),
16
+ client.catalogue.getCategories(),
17
+ client.catalogue.getCollections(),
18
+ ]);
19
+
20
+ const products: Product[] = productsRes.ok ? productsRes.value.items : [];
21
+ const categories = categoriesRes.ok ? categoriesRes.value : [];
22
+ const collections = collectionsRes.ok ? collectionsRes.value : [];
23
+
24
+ const lines: string[] = [];
25
+ lines.push(`# ${brand.name}`);
26
+ lines.push("");
27
+ lines.push(`> ${brand.llms.summary}`);
28
+ lines.push("");
29
+ lines.push("## Browse");
30
+ lines.push(`- [Home](${SITE_URL}/)`);
31
+ lines.push(`- [Shop](${SITE_URL}/shop): Full catalogue with filter and sort.`);
32
+
33
+ if (categories.length > 0) {
34
+ lines.push("");
35
+ lines.push("## Categories");
36
+ for (const c of categories) {
37
+ lines.push(
38
+ `- [${c.name}](${SITE_URL}/categories/${c.slug})${c.description ? `: ${c.description}` : ""}`,
39
+ );
40
+ }
41
+ }
42
+
43
+ if (collections.length > 0) {
44
+ lines.push("");
45
+ lines.push("## Collections");
46
+ for (const c of collections) {
47
+ lines.push(
48
+ `- [${c.name}](${SITE_URL}/collections/${c.slug})${c.description ? `: ${c.description}` : ""}`,
49
+ );
50
+ }
51
+ }
52
+
53
+ if (products.length > 0) {
54
+ lines.push("");
55
+ lines.push("## Products");
56
+ for (const p of products) {
57
+ const slug = p.slug ?? p.id;
58
+ const price = `${p.currency ?? brand.currency} ${p.default_price}`;
59
+ const desc = p.description ? ` — ${p.description.replace(/\s+/g, " ").slice(0, 200)}` : "";
60
+ lines.push(`- [${p.name}](${SITE_URL}/products/${slug}) (${price})${desc}`);
61
+ }
62
+ }
63
+
64
+ lines.push("");
65
+ lines.push("## Information");
66
+ lines.push(`- [About](${SITE_URL}/about)`);
67
+ lines.push(`- [Support / FAQ](${SITE_URL}/faq)`);
68
+ lines.push(`- [Terms of Service](${SITE_URL}/terms)`);
69
+ lines.push(`- [Privacy Policy](${SITE_URL}/privacy)`);
70
+ lines.push(`- [Sitemap (XML)](${SITE_URL}/sitemap.xml)`);
71
+ lines.push("");
72
+ lines.push("## Contact");
73
+ lines.push(`- Email: ${brand.contact.email}`);
74
+ lines.push(`- Phone: ${brand.contact.phone}`);
75
+ lines.push(`- Address: ${brand.contact.address}`);
76
+
77
+ return lines.join("\n") + "\n";
78
+ }
79
+
80
+ /**
81
+ * `/llms.txt` — machine-readable site index for LLMs (per llmstxt.org).
82
+ * Lets coding agents and chat assistants find products, categories, and
83
+ * support pages without scraping HTML. Plain Markdown so it streams cheaply
84
+ * into context windows.
85
+ */
86
+ export async function GET(): Promise<Response> {
87
+ const body = await buildLlmsTxt();
88
+ return new Response(body, {
89
+ headers: {
90
+ "Content-Type": "text/plain; charset=utf-8",
91
+ "Cache-Control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
92
+ },
93
+ });
94
+ }
@@ -0,0 +1,39 @@
1
+ import type { Metadata } from "next";
2
+ import Link from "next/link";
3
+ import { brand } from "@/lib/brand";
4
+
5
+ export const metadata: Metadata = {
6
+ title: `Page not found — ${brand.name}`,
7
+ description: "We couldn't find that page.",
8
+ };
9
+
10
+ export default function NotFound() {
11
+ return (
12
+ <section className="max-w-2xl mx-auto px-6 sm:px-8 py-20 text-center">
13
+ <p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-3">
14
+ 404
15
+ </p>
16
+ <h1 className="text-[clamp(2.5rem,5vw,4rem)] font-bold mb-4 -tracking-[0.03em]">
17
+ Page not found.
18
+ </h1>
19
+ <p className="text-muted-foreground leading-relaxed mb-8">
20
+ The URL you followed might be old, a typo, or pointing at a product
21
+ that&apos;s no longer in stock. Try the menu or head back home.
22
+ </p>
23
+ <div className="flex flex-wrap items-center justify-center gap-3">
24
+ <Link
25
+ href="/shop"
26
+ className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md bg-primary text-primary-foreground font-semibold text-sm hover:bg-primary/90 transition-colors"
27
+ >
28
+ Browse the shop
29
+ </Link>
30
+ <Link
31
+ href="/"
32
+ className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md border border-border hover:bg-muted transition-colors text-sm font-medium"
33
+ >
34
+ Back home
35
+ </Link>
36
+ </div>
37
+ </section>
38
+ );
39
+ }
@@ -12,11 +12,11 @@ import { TradeInCta } from "@/components/trade-in-cta";
12
12
  import { Newsletter } from "@/components/newsletter";
13
13
  import { SectionHeading } from "@/components/section-heading";
14
14
  import { StoreProductCard } from "@/components/store-product-card";
15
+ import { brand } from "@/lib/brand";
15
16
 
16
17
  export const metadata: Metadata = {
17
- title: "Currents Electronics — Tech, in stock, in Accra",
18
- description:
19
- "Authorised dealer for Apple, Samsung, Sony, Bose. Same-day delivery, two-year warranty, instalment payments — across Accra and West Africa.",
18
+ title: brand.hero.title,
19
+ description: brand.description,
20
20
  };
21
21
 
22
22
  interface CollectionWithProducts {
@@ -57,55 +57,7 @@ async function getHomeData() {
57
57
  };
58
58
  }
59
59
 
60
- const TRUST_ITEMS = [
61
- {
62
- label: "Delivery",
63
- value: "Same-day in Accra",
64
- description: "Orders before 4pm, free over GH₵500.",
65
- icon: (
66
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-5 h-5" aria-hidden>
67
- <path d="M3 7h12v8H3zM15 10h4l3 3v2h-7z" strokeLinejoin="round" />
68
- <circle cx="7" cy="17" r="1.5" />
69
- <circle cx="18" cy="17" r="1.5" />
70
- </svg>
71
- ),
72
- },
73
- {
74
- label: "Warranty",
75
- value: "2 years on everything",
76
- description: "1yr manufacturer + 1yr Currents.",
77
- icon: (
78
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-5 h-5" aria-hidden>
79
- <path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6l8-3z" strokeLinejoin="round" />
80
- <path d="M9 12l2 2 4-4" strokeLinecap="round" strokeLinejoin="round" />
81
- </svg>
82
- ),
83
- },
84
- {
85
- label: "Payment",
86
- value: "Pay in 3, interest-free",
87
- description: "Or 6/12 months via Fidelity Bank.",
88
- icon: (
89
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-5 h-5" aria-hidden>
90
- <rect x="3" y="6" width="18" height="12" rx="2" />
91
- <line x1="3" y1="10" x2="21" y2="10" />
92
- </svg>
93
- ),
94
- },
95
- {
96
- label: "Genuine",
97
- value: "Authorised dealer",
98
- description: "Direct from Apple, Samsung, Sony, Bose.",
99
- icon: (
100
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-5 h-5" aria-hidden>
101
- <circle cx="12" cy="12" r="9" />
102
- <path d="M8 12l3 3 5-6" strokeLinecap="round" strokeLinejoin="round" />
103
- </svg>
104
- ),
105
- },
106
- ];
107
-
108
- const HERO_IMAGE =
60
+ const HERO_FALLBACK_IMAGE =
109
61
  "https://images.unsplash.com/photo-1592899677977-9c10ca588bbd?w=1200&h=1200&fit=crop&auto=format&q=85";
110
62
 
111
63
  export default async function HomePage() {
@@ -117,37 +69,28 @@ export default async function HomePage() {
117
69
  <FeatureHero
118
70
  eyebrow="Featured · in stock"
119
71
  badge="Just landed"
120
- title={
121
- <>
122
- Built for the way<br />
123
- you actually work.
124
- </>
125
- }
126
- description={
127
- heroProduct?.description ??
128
- "Apple, Samsung, Sony, Bose — direct from the source, with a two-year warranty and same-day Accra delivery on every order."
129
- }
72
+ title={brand.hero.title}
73
+ description={heroProduct?.description ?? brand.hero.subtitle}
130
74
  primaryCta={{
131
- label: heroProduct ? `Shop ${heroProduct.name}` : "Shop the menu",
132
- href: heroProduct ? `?product=${heroProduct.slug ?? heroProduct.id}` : "/shop",
75
+ label: heroProduct ? `Shop ${heroProduct.name}` : brand.hero.primaryCtaLabel,
76
+ href: heroProduct ? `/products/${heroProduct.slug ?? heroProduct.id}` : "/shop",
133
77
  }}
134
- secondaryCta={{ label: "See deals", href: "/categories/deals" }}
135
- imageUrl={heroProduct?.image_url ?? heroProduct?.images?.[0] ?? HERO_IMAGE}
78
+ secondaryCta={
79
+ brand.hero.secondaryCtaLabel && brand.hero.secondaryCtaHref
80
+ ? { label: brand.hero.secondaryCtaLabel, href: brand.hero.secondaryCtaHref }
81
+ : undefined
82
+ }
83
+ imageUrl={heroProduct?.image_url ?? heroProduct?.images?.[0] ?? HERO_FALLBACK_IMAGE}
136
84
  imageAlt={heroProduct?.name ?? "Featured product"}
137
85
  />
138
86
 
139
- <TrustBar items={TRUST_ITEMS} />
87
+ <TrustBar />
140
88
 
141
89
  <Suspense fallback={<CategoryTilesSkeleton />}>
142
90
  <CategoryTiles categories={categories} />
143
91
  </Suspense>
144
92
 
145
- <PromoBanner
146
- badge="Limited · ends Sunday"
147
- title="Trade in your old phone, get up to GH₵3,500 off."
148
- body="Send us your last-gen iPhone or Galaxy. We'll quote within 48 hours and credit the value toward your next upgrade."
149
- cta={{ label: "Start trade-in", href: "/about" }}
150
- />
93
+ <PromoBanner />
151
94
 
152
95
  <section className="max-w-7xl mx-auto px-6 sm:px-8 py-14 sm:py-20">
153
96
  <SectionHeading
@@ -1,100 +1,43 @@
1
1
  import type { Metadata } from "next";
2
+ import { brand } from "@/lib/brand";
2
3
 
3
4
  export const metadata: Metadata = {
4
- title: "Privacy Policy — Currents Electronics",
5
- description:
6
- "How Currents Electronics collects, uses, and protects your personal data.",
5
+ title: `Privacy Policy — ${brand.name}`,
6
+ description: `How ${brand.name} collects, uses, and protects your personal data.`,
7
7
  };
8
8
 
9
9
  export default function PrivacyPage() {
10
+ const p = brand.privacy;
10
11
  return (
11
12
  <article className="max-w-3xl mx-auto px-8 py-16 prose prose-lg max-w-none">
12
13
  <p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-2 not-prose">
13
- Privacy
14
+ {p.eyebrow}
14
15
  </p>
15
16
  <h1 className="text-[clamp(2.25rem,5vw,3.5rem)] font-bold mb-2 -tracking-[0.025em]">
16
- Privacy Policy
17
+ {p.title}
17
18
  </h1>
18
19
  <p className="text-sm text-muted-foreground not-prose mb-10">
19
- Last updated: 1 May 2026
20
+ Last updated: {p.lastUpdated}
20
21
  </p>
21
22
 
22
23
  <section className="space-y-5 leading-relaxed text-foreground/90">
23
- <h2 className="text-2xl font-semibold mt-0 -tracking-[0.02em]">
24
- What we collect
25
- </h2>
26
- <p>
27
- We collect what we need to fulfil your order: name, phone, delivery
28
- address, email, and the items in your order. For warranty service
29
- and trade-ins, we also collect device serial numbers. Payment details
30
- are processed by our payment partners (Paystack, Stripe, Fidelity
31
- Bank) and never stored on our servers.
32
- </p>
33
-
34
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">
35
- How we use it
36
- </h2>
37
- <ul className="list-disc pl-6 space-y-2">
38
- <li>To prepare, deliver, and confirm your order.</li>
39
- <li>To register product warranties on your behalf.</li>
40
- <li>To send order updates by SMS and email.</li>
41
- <li>
42
- To send occasional product news and deals — only if you opted in.
43
- Unsubscribe anytime in one click.
44
- </li>
45
- <li>
46
- To analyse aggregated, anonymised browsing patterns so we can
47
- improve the site and recommend products.
48
- </li>
49
- </ul>
50
-
51
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">
52
- Who we share it with
53
- </h2>
54
- <p>
55
- We share data only with the partners required to fulfil your order
56
- and warranty: payment processors (Paystack, Stripe, Fidelity Bank),
57
- delivery couriers (DHL, local riders), manufacturer warranty portals
58
- (for serial registration), and our email/SMS providers. We do not
59
- sell or rent personal data to third parties — ever.
60
- </p>
61
-
62
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">Cookies</h2>
63
- <p>
64
- We use a small number of strictly-necessary cookies to keep your cart
65
- working and your session signed in, plus optional analytics cookies
66
- (you can disable these in our cookie banner).
67
- </p>
68
-
69
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">
70
- Your rights
71
- </h2>
72
- <p>
73
- Under the Ghana Data Protection Act, 2012 (Act 843), you have the
74
- right to access the data we hold about you, correct it, or have it
75
- deleted (subject to our tax-record retention obligations). Email{" "}
76
- <a
77
- href="mailto:privacy@currentselectronics.test"
78
- className="text-primary font-semibold hover:underline"
79
- >
80
- privacy@currentselectronics.test
81
- </a>{" "}
82
- and we&apos;ll respond within 14 days.
83
- </p>
84
-
85
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">Retention</h2>
86
- <p>
87
- We keep order records for 7 years to comply with Ghanaian tax law.
88
- Warranty records are retained for the life of the warranty plus 24
89
- months. Marketing-list opt-ins are kept until you unsubscribe.
90
- </p>
91
-
92
- <h2 className="text-2xl font-semibold -tracking-[0.02em]">Changes</h2>
93
- <p>
94
- If we make material changes to this policy, we&apos;ll email
95
- customers on our marketing list and update the &quot;last updated&quot;
96
- date above.
97
- </p>
24
+ {p.sections.map((s) => (
25
+ <div key={s.heading}>
26
+ <h2 className="text-2xl font-semibold mt-0 -tracking-[0.02em]">{s.heading}</h2>
27
+ {typeof s.body === "string" ? (
28
+ <p>{s.body}</p>
29
+ ) : (
30
+ <>
31
+ <p>{s.body.intro}</p>
32
+ <ul className="list-disc pl-6 space-y-2">
33
+ {s.body.bullets.map((b) => (
34
+ <li key={b}>{b}</li>
35
+ ))}
36
+ </ul>
37
+ </>
38
+ )}
39
+ </div>
40
+ ))}
98
41
  </section>
99
42
  </article>
100
43
  );