AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Projects
  3. Castello Is

Castello Is

June 1, 20254 min read
View Project
Next JsTypescriptTailwind CSSPrismic
1 / 4

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).

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.ts

Content 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!