diff --git a/.editorconfig b/.editorconfig index 0206b56..01066b6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,7 @@ root = true -[*.{ts,tsx,json}] +[*.{ts,tsx,json,yml,yaml}] tab_width = 2 indent_style = tab end_of_line = lf \ No newline at end of file diff --git a/package.json b/package.json index 1a9751b..dffc1de 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "clsx": "^2.1.0", "contentful": "^10.6.21", "embla-carousel-react": "^8.0.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.323.0", "luxon": "^3.4.4", "next": "14.1.0", @@ -52,6 +53,7 @@ }, "devDependencies": { "@total-typescript/ts-reset": "^0.5.1", + "@types/js-cookie": "^3.0.6", "@types/luxon": "^3.4.2", "@types/node": "^20", "@types/react": "^18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a20d6ce..5a06eab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ dependencies: embla-carousel-react: specifier: ^8.0.0 version: 8.0.0(react@18.2.0) + js-cookie: + specifier: ^3.0.5 + version: 3.0.5 lucide-react: specifier: ^0.323.0 version: 0.323.0(react@18.2.0) @@ -118,6 +121,9 @@ devDependencies: '@total-typescript/ts-reset': specifier: ^0.5.1 version: 0.5.1 + '@types/js-cookie': + specifier: ^3.0.6 + version: 3.0.6 '@types/luxon': specifier: ^3.4.2 version: 3.4.2 @@ -1475,6 +1481,10 @@ packages: resolution: {integrity: sha512-AqlrT8YA1o7Ff5wPfMOL0pvL+1X+sw60NN6CcOCqs658emD6RfiXhF7Gu9QcfKBH7ELY2nInLhKSCWVoNL70MQ==} dev: true + /@types/js-cookie@3.0.6: + resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} + dev: true + /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true @@ -3177,6 +3187,11 @@ packages: resolution: {integrity: sha512-qiaQhtQRw6YrOaOj0v59h3R6hUY9NvxBmmnMfKemkqYmBB0tEc97NbLP7ix44VP5p9/0YHG8Vyhzuo5YBNwviA==} dev: false + /js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} diff --git a/src/app/student/events/[id]/page.tsx b/src/app/student/events/[id]/page.tsx index 5842a11..7cbe479 100644 --- a/src/app/student/events/[id]/page.tsx +++ b/src/app/student/events/[id]/page.tsx @@ -1,8 +1,9 @@ import EventDetails from "@/app/student/events/_components/EventDetails" import { Page } from "@/components/shared/Page" +import { feature } from "@/components/shared/feature" import { fetchEvents } from "@/components/shared/hooks/api/useEvents" -import { notFound } from "next/navigation" import { Metadata } from "next" +import { notFound } from "next/navigation" async function getEvent(eventId: string) { const events = await fetchEvents() @@ -39,6 +40,10 @@ export default async function EventDetailsPage({ }: { params: { id: string } }) { + if (!feature("EVENT_PAGE")) { + return notFound() + } + const event = await getEvent(params.id) return ( diff --git a/src/app/student/events/page.tsx b/src/app/student/events/page.tsx index ed0e081..dc6dcbd 100644 --- a/src/app/student/events/page.tsx +++ b/src/app/student/events/page.tsx @@ -1,8 +1,13 @@ import { EventsTimeline } from "@/app/student/events/_components/EventsTimeLine" import { Page } from "@/components/shared/Page" +import { feature } from "@/components/shared/feature" import { fetchEvents } from "@/components/shared/hooks/api/useEvents" +import { notFound } from "next/navigation" export default async function StudentEventPage() { + if (!feature("EVENT_PAGE")) { + return notFound() + } const events = await fetchEvents() return ( diff --git a/src/components/shared/NavigationMenu.tsx b/src/components/shared/NavigationMenu.tsx index 5f286fe..0139d52 100644 --- a/src/components/shared/NavigationMenu.tsx +++ b/src/components/shared/NavigationMenu.tsx @@ -4,6 +4,7 @@ import Link from "next/link" import * as React from "react" import { Page } from "@/components/shared/Page" +import { feature } from "@/components/shared/feature" import { useScreenSize } from "@/components/shared/hooks/useScreenSize" import { NavigationMenu as BaseNavigationMenu, @@ -22,62 +23,79 @@ import { DateTime } from "luxon" import Image from "next/image" import { useEffect, useState } from "react" -const companyLinks: { title: string; href: string; description: string }[] = [ +type NavigationLink = { + title: string + href: string + description: string + enabled: boolean +} + +const companyLinks: NavigationLink[] = [ { title: "Registration", href: "https://register.armada.nu/register", - description: `Signup as an exhibitor for the fair ${DateTime.now().year}` + description: `Signup as an exhibitor for the fair ${DateTime.now().year}`, + enabled: true }, { title: "Packages", href: "/exhibitor/packages", - description: "See what we have to offer" + description: "See what we have to offer", + enabled: true }, { title: "Why Armada", href: "/exhibitor", - description: "The industry's top engineers come from KTH" + description: "The industry's top engineers come from KTH", + enabled: true }, { title: "Timeline - Step by Step", href: "/exhibitor/timeline", - description: "Your guide to the fair" + description: "Your guide to the fair", + enabled: true } ] -const studentLinks: { title: string; href: string; description: string }[] = [ +const studentLinks: NavigationLink[] = [ { title: "Exhibitors", href: "/student/exhibitors", - description: `Get an in depth look at the companies attending the fair` + description: `Get an in depth look at the companies attending the fair`, + enabled: true }, { title: "Events", href: "/student/events", - description: "See the events leading up to the fair" + description: "See the events leading up to the fair", + enabled: feature("EVENT_PAGE") }, { title: "Recruitment", href: "/student/recruitment", - description: `Join Armada ${DateTime.now().year}. See which roles are available` + description: `Join Armada ${DateTime.now().year}. See which roles are available`, + enabled: true } ] -const aboutLinks: { title: string; href: string; description: string }[] = [ +const aboutLinks: NavigationLink[] = [ { title: "About Armada", href: "/about", - description: `Get to know the Armada organization` + description: `Get to know the Armada organization`, + enabled: true }, - /* { + { title: "Events", href: "/student/events", - description: "See the events leading up to the fair" - }, */ + description: "See the events leading up to the fair", + enabled: feature("EVENT_PAGE") + }, { title: "Team", href: "/about/team", - description: `Get to know the team working on Armada ${DateTime.now().year}` + description: `Get to know the team working on Armada ${DateTime.now().year}`, + enabled: true } ] @@ -136,44 +154,50 @@ export function NavigationMenu( Student - {studentLinks.map(component => ( -
- setSheetOpen(false)} - className="font-bebas-neue text-xl text-melon-700" - href={component.href}> - {component.title} - -
- ))} + {studentLinks + .filter(link => link.enabled) + .map(component => ( +
+ setSheetOpen(false)} + className="font-bebas-neue text-xl text-melon-700" + href={component.href}> + {component.title} + +
+ ))} Exhibitor - {companyLinks.map(component => ( -
- setSheetOpen(false)} - className="font-bebas-neue text-xl text-melon-700" - href={component.href}> - {component.title} - -
- ))} + {companyLinks + .filter(link => link.enabled) + .map(component => ( +
+ setSheetOpen(false)} + className="font-bebas-neue text-xl text-melon-700" + href={component.href}> + {component.title} + +
+ ))} About us - {aboutLinks.map(component => ( -
- setSheetOpen(false)} - className="font-bebas-neue text-xl text-melon-700" - href={component.href}> - {component.title} - -
- ))} + {aboutLinks + .filter(link => link.enabled) + .map(component => ( +
+ setSheetOpen(false)} + className="font-bebas-neue text-xl text-melon-700" + href={component.href}> + {component.title} + +
+ ))} {/** BaseNavigationMenu is used for desktop navigation */} @@ -201,14 +225,16 @@ export function NavigationMenu(
    - {studentLinks.map(component => ( - - {component.description} - - ))} + {studentLinks + .filter(link => link.enabled) + .map(component => ( + + {component.description} + + ))}
@@ -220,14 +246,16 @@ export function NavigationMenu(
    - {companyLinks.map(component => ( - - {component.description} - - ))} + {companyLinks + .filter(link => link.enabled) + .map(component => ( + + {component.description} + + ))}
@@ -239,14 +267,16 @@ export function NavigationMenu(
    - {aboutLinks.map(component => ( - - {component.description} - - ))} + {aboutLinks + .filter(link => link.enabled) + .map(component => ( + + {component.description} + + ))}
diff --git a/src/components/shared/feature.ts b/src/components/shared/feature.ts index d167a9f..9fcf08c 100644 --- a/src/components/shared/feature.ts +++ b/src/components/shared/feature.ts @@ -1,12 +1,13 @@ import featureFlags from "@/feature_flags" -import { cookies } from "next/headers" +import Cookies from "js-cookie" export function feature(feature: keyof typeof featureFlags) { - const rawOverrides = cookies().get("vercel-flag-overrides") + let rawOverrides = Cookies.get("vercel-flag-overrides") + const overrides = rawOverrides == null ? {} - : (JSON.parse(rawOverrides.value) as Record) + : (JSON.parse(rawOverrides) as Record) if (overrides[feature] != null) { return overrides[feature] @@ -15,3 +16,4 @@ export function feature(feature: keyof typeof featureFlags) { } return false } +const test = "test" diff --git a/src/feature_flags.ts b/src/feature_flags.ts index b56d276..86d8d08 100644 --- a/src/feature_flags.ts +++ b/src/feature_flags.ts @@ -1,10 +1,20 @@ import { FlagDefinitionsType } from "@vercel/flags" -export const FEATURE_FLAG_DEFINITIONS = {} satisfies FlagDefinitionsType +export const FEATURE_FLAG_DEFINITIONS = { + EVENT_PAGE: { + description: "Access to Event Page", + options: [ + { value: true, label: "Show" }, + { value: false, label: "Hidden" } + ] + } +} satisfies FlagDefinitionsType export const FEATURE_FLAGS: Record< keyof typeof FEATURE_FLAG_DEFINITIONS, boolean -> = {} +> = { + EVENT_PAGE: false +} export default FEATURE_FLAGS