Castello Is




Overview
Castello Is is the customer-facing ordering and marketing website for Castello, an Italian restaurant group with branches in Reykjavik (Laugavegur and Storhothi). The site lets visitors browse pizzas, kebab, and offers, customise a pizza down to a half-and-half split, check the allergen breakdown of every item, and place an order for pickup or delivery in Icelandic or English.
As with the other VISKA customer sites, Prismic owns the marketing content and the menu, while the product catalog, pricing, cart, and checkout are driven by the shared Upsell platform through the @upsell/kit library and the public-api.upsell.is/v2 API. There is no local database — Prismic is the content source and SWR (via the kit) handles client-side data fetching.
Tech Stack & Rationale
Layer | Technology | Why |
|---|---|---|
Framework | Next.js 14 (App Router), React 18 | Server-first rendering with locale-based route groups ((main), (clean), (prismic)) |
Language | TypeScript | Strict typing across slices, kit types, and API responses |
Styling | Tailwind CSS 3.4 | Rapid, consistent brand styling without custom CSS files |
CMS | Prismic + Slice Machine | Editors manage pages, layout, and slices without code changes |
Client data fetching | SWR 2.2 (via @upsell/kit) | Revalidation and caching for cart, checkout, and client state |
Business logic | @upsell/kit + public-api.upsell.is/v2 (Axios) | Shared cart, checkout, and Apple Pay logic with a MobileApp-authenticated store ID |
i18n | LinguiJS (is, en) + Crowdin | Compile-time message catalogs, Icelandic-first locale redirect |
Maps | Mapbox GL + react-map-gl | Store locator |
Animation | GSAP, Swiper, Lottie, Framer Motion | Hero motion and carousels |
Monitoring | Sentry | Error tracking in production |
Hosting | Vercel | Preview + production deployments via Nx |
Architecture
A request flows from the locale middleware through server-rendered pages, then hands off to SWR-backed client components that talk to the Upsell API. Prismic content is fetched server-side with tag-based caching and preview support.
The flow runs: Browser request (/is/menu) → middleware.ts (locale redirect → is) → Server Components (RSC + generateMetadata) → SWR hooks (client revalidation) → public-api (upsell.is/v2) → Vercel (edge / CDN); Browser request (/is/menu) → middleware.ts (locale redirect → is) → Prismic client (tag cache + preview) → @upsell/kit (cart · checkout).
- Locale routing — middleware.ts reads the request pathname and, when no locale prefix is present, redirects to /is/... (Icelandic default). API and well-known paths are exempt.
- Server rendering — (main) pages are React Server Components that fetch Prismic pages documents (with their linked layouts document) through a tag-cached client, then render the slice zone.
- Client interactivity — interactive features (cart, pizza customizer, allergen table) hydrate into client components that read the product catalog through @upsell/kit, with SWR managing revalidation and optimistic cart state.
- Checkout — the (clean) route group renders checkout steps (shipping, summary, verification) without the site chrome; payment goes through the Upsell API with Apple Pay support via the useApplePay hook and OTP verification via react18-input-otp.
- Larger orders — the staerri-pantanir route handles catering-style bulk orders, and the /offers, /pizzas, and /kebab URLs redirect into anchored menu sections.
Folder Structure
customers/castello-web/
├── app/[locale]/
│ ├── (main)/
│ │ ├── (customization)/ # products/[productID], deals/[dealID]
│ │ ├── staerri-pantanir/ # larger/catering orders
│ │ ├── store/ · login/ · profile/
│ ├── (clean)/checkout/ # shipping · summary · verification
│ ├── (prismic)/[[...slug]]/ # CMS-driven pages + slice-simulator
│ └── layout.tsx
├── components/ # auth, cart, checkout, deal, input, product, profile, store…
├── slices/ # 14 slices (Hero, Menu, AllergensTable, StoreLocations, …)
├── customtypes/ # pages, layouts, top_banner
├── constants/ # branches, order, products
├── lib/ # prismic.ts, api.ts, generateMetaData.ts, linkResolver.ts, hooks/
├── locales/translations/ # en.po, is.po (Crowdin)
├── middleware.ts · appRouterI18n.ts · prismicio.ts
└── next.config.js · tailwind.config.tsContent Model
Prismic is the single content source. Three custom types drive the site:
Custom type | Kind | Purpose |
|---|---|---|
pages | Repeatable | Marketing pages — uid, page_title, a layout link, a slice zone, and SEO metadata (meta_title, meta_description, meta_image) |
layouts | Repeatable | Site chrome composed of navbar, children, and footer slices; linked from each pages document |
top_banner | Singleton | An optional promo bar (paragraph, cta_text, cta_url, active) surfaced by the useTopBanner hook |
The pages slice zone exposes 11 slices: hero, menu, featured_products, category_shortcut, allergens_table, store_locations, text_image_banner, paragraph, and the form slices contact_form, career_form, and catering_form.
Impact & Results
- In production for the Castello restaurant group in Reykjavik, with half-and-half pizza customization and bilingual ordering.
- One of 16+ customer sites served by the shared VISKA monorepo platform.
My Contributions
Worked on the Castello site as part of the VISKA monorepo team:
- Built the half-and-half pizza customization flow so a pizza can be split between two toppings.
- Added the allergen page and its Prismic content (allergen table slice and page wiring).
- Added the paragraph/contact slice and iterated on the main menu UI.
- Improved responsiveness and loading states, including skeleton loaders for the menu.
- Fixed a variation-selection bug and synced Icelandic and English Crowdin translations.
References
[1] Castello, "Castello — Pizzeria," castello.is, 2025. [Online]. Available: https://castello.is
[2] Vercel, "Next.js Documentation," nextjs.org. [Online]. Available: https://nextjs.org/docs
[3] Prismic, "Prismic Documentation," prismic.io. [Online]. Available: https://prismic.io/docs
[4] Vercel, "SWR — React Hooks for Data Fetching," swr.vercel.app. [Online]. Available: https://swr.vercel.app
[5] LinguiJS, "LinguiJS — Internationalization," lingui.dev. [Online]. Available: https://lingui.dev
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!