Subway Iceland



Overview
Subway Iceland is the customer-facing ordering and marketing website for the Icelandic Subway franchise. The site lets visitors browse the sandwich menu, customise each sandwich step by step, order party platters ("Veisluplattar"), check the nutrition table, schedule a pre-order for a future pickup time, and locate branches on a Mapbox map.
Like the other VISKA customer sites, this is a marketing/ordering shell: Prismic owns the marketing content and the menu, while the product catalog, pricing, cart, and checkout come from the shared Upsell platform through @upsell/kit 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. The site is Icelandic-only (single locale) and deployed to Cloudflare Workers.
Tech Stack & Rationale
Layer | Technology | Why |
|---|---|---|
Framework | Next.js 14 (App Router), React 18 | Server-first rendering with route groups ((main), (user), (guest), (prismic)) |
Language | TypeScript | Strict typing across slices, kit types, and API responses |
Styling | Tailwind CSS 3.4 | Rapid, consistent brand styling |
CMS | Prismic + Slice Machine | Editors manage pages, layout, store data, 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 |
Maps | Mapbox GL + react-map-gl | Store locator and pickup-map checkout step |
Forms & email | Formik + Yup, SendGrid | Contact and order-related email |
Animation | GSAP, Slick, Framer Motion, Lottie | Hero motion, carousels, running-text marquee |
Monitoring | Sentry | Error tracking in production |
Hosting | Cloudflare Workers via OpenNext (migrated from Vercel) | Edge deployment of the Next.js standalone build |
Architecture
A request is served at the Cloudflare edge, flows 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 (/menu) → Cloudflare edge (OpenNext worker) → Server Components (RSC + generateMetadata) → SWR hooks (client revalidation) → public-api (upsell.is/v2) → SendGrid (order email); Browser request (/menu) → Cloudflare edge (OpenNext worker) → Prismic client (tag cache + preview) → @upsell/kit (cart · checkout).
- Edge serving — the standalone Next.js build runs as a Cloudflare Worker through OpenNext; the root app/layout.tsx wraps the whole site and the (prismic) group resolves CMS pages from the catch-all [[...slug]] route.
- Server rendering — (main) pages (menu, store, store-list, upsell) 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 — the sandwich customizer, party-platter builder, and cart hydrate into client components that read the product catalog through @upsell/kit, with SWR managing revalidation and optimistic cart state.
- Scheduled orders — a pre-order flow (lib/checkPreOrder.ts, scheduling contexts, and branch gating in constants/store.ts) lets customers pick a future pickup slot and restrict branches that only accept scheduled orders.
- Checkout — the (user) group renders the checkout funnel (pickup, pickup-map, summary, verification, success); payment goes through the Upsell API with Apple Pay via useApplePay and OTP verification via react18-input-otp.
Folder Structure
customers/subway-web/
├── app/(routes)/
│ ├── (main)/ # menu · store · store-list · upsell
│ │ ├── (customization)/ # products/[productID], deals/[dealID]
│ │ ├── (guest)/login/
│ │ └── (user)/checkout/ # pickup · pickup-map · summary · verification · success
│ │ └── profile/order/[id]
│ ├── (prismic)/[[...slug]]/ # CMS-driven pages
│ └── layout.tsx
├── components/ # auth, cart, checkout, deal, input, map, menu, product, profile…
├── contexts/ # DealContext, CustomizationStepContext, layout, meta
├── slices/ # 16 slices (Hero, MenuListMobile, NutritionTable, StoreBanner, …)
├── customtypes/ # app_pages, layouts, pages, store_data, top_banner, variation_setup
├── constants/ # checkout, customization, deals, extra, map, products, store, upsell
├── lib/ # api.ts, deals.ts, checkPreOrder.ts, locationSorting.ts, sendEmail.ts, hooks/
├── app/layout.tsx · prismicio.ts
└── next.config.js · wrangler.toml · open-next.config.tsContent Model
Prismic is the single content source. Six 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, meta_keywords) |
app_pages | Repeatable | App-specific pages with an empty slice zone and SEO metadata |
layouts | Repeatable | Site chrome composed of navigation_bar, children, and footer slices; linked from each pages document |
store_data | Singleton | Store locator config — initial_coordinate, zoom, and a branches Group (branch_id, coordinate, gmap) |
variation_setup | Singleton | Variation attributes — an attributes Group (attribute_id, attribute_name, image, calories) |
top_banner | Singleton | An optional promo bar (paragraph, button_text, href, active) |
The pages slice zone exposes 13 slices, notably hero, text_with_image_hero, deal_section, featured_product, menu_list_mobile, nutrition_table, store_banner, running_text, content_with_tab, and the account slices order_history and order_status_popup.
Impact & Results
- In production for the Subway franchise in Iceland — step-by-step sandwich customization, party platters, and scheduled pre-orders.
- One of 16+ customer sites served by the shared VISKA monorepo platform.
My Contributions
Worked on the Subway Iceland site as part of the VISKA monorepo team:
- Built the scheduled pre-order flow: schedule list modal, scheduling template categories, pickup-hour limits by date, pre-order tags, the Borgarnes branch's scheduled-order-only rule, empty-schedule handling, and the post-checkout redirect.
- Built the party platter ("Veisluplattar") ordering flow with branch gating, labels, and customization.
- Worked on the store locator and map: branch search, map markers, store-map navigation, branch cards, and the Akureyri branch.
- Added the contact form, the ingredient page and its slice, card animations, the extra-confirmation modal, and gift-card handling.
- Fixed navbar, cart, and UX issues (profile name, menu icon, cart z-index, hidden cart) and improved translations.
References
[1] Subway Iceland, "Subway — Iceland," subway.is, 2024. [Online]. Available: https://subway.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] OpenNext, "OpenNext for Cloudflare," opennext.js.org. [Online]. Available: https://opennext.js.org/cloudflare
[5] Vercel, "SWR — React Hooks for Data Fetching," swr.vercel.app. [Online]. Available: https://swr.vercel.app
Comments
Leave a Comment
You must be signed in to comment
0 Comments
No comments yet. Be the first to comment!