diff --git a/lighthouserc.cjs b/lighthouserc.cjs index a60b47bb..9cdbd3bc 100644 --- a/lighthouserc.cjs +++ b/lighthouserc.cjs @@ -15,6 +15,8 @@ const config = { 'http://localhost:3000/en/storage', 'http://localhost:3000/en/storage/shopping-cart', 'http://localhost:3000/en/shift-schedule', + 'http://localhost:3000/en/rules', + 'http://localhost:3000/en/rules/1', ], startServerCommand: 'bun run start', }, diff --git a/messages/en.json b/messages/en.json index e50eb064..99dc38bb 100644 --- a/messages/en.json +++ b/messages/en.json @@ -92,6 +92,7 @@ "shiftSchedule": "Shift Schedule", "desktopNavMenu": "{open, select, true {Open} other {Close}} navigation menu", "goToMatrix": "Go to matrix", + "rules": "Rules", "changeLocale": "Change language", "toggleTheme": "Toggle theme", "light": "Light", @@ -215,5 +216,10 @@ "api": { "tooManyRequests": "Too many requests, please try again later", "notAuthenticated": "Not authenticated" + }, + "rules": { + "title": "Rules", + "forEveryone": "For everyone", + "internal": "Internal rules" } } diff --git a/messages/no.json b/messages/no.json index 8a17bd8e..61a0228b 100644 --- a/messages/no.json +++ b/messages/no.json @@ -92,6 +92,7 @@ "shiftSchedule": "Vaktliste", "desktopNavMenu": "{open, select, true {Åpne} other {Lukk}} navigasjonsmeny", "goToMatrix": "Dra til matrix", + "rules": "Rules", "changeLocale": "Bytt språk", "toggleTheme": "Bytt tema", "light": "Lys", @@ -215,5 +216,10 @@ "api": { "tooManyRequests": "For mange forespørsler. Vennligst vent noen minutter og prøv igjen", "notAuthenticated": "Ikke autentisert" + }, + "rules": { + "title": "Regler", + "forEveryone": "For alle", + "internal": "Interne regler" } } diff --git a/src/app/[locale]/(default)/rules/(main)/layout.tsx b/src/app/[locale]/(default)/rules/(main)/layout.tsx new file mode 100644 index 00000000..a6912824 --- /dev/null +++ b/src/app/[locale]/(default)/rules/(main)/layout.tsx @@ -0,0 +1,21 @@ +import { getTranslations, setRequestLocale } from 'next-intl/server'; + +type RulesLayoutProps = { + children: React.ReactNode; + params: Promise<{ locale: string }>; +}; + +export default async function RulesLayout({ + children, + params, +}: RulesLayoutProps) { + const { locale } = await params; + setRequestLocale(locale); + const t = await getTranslations('rules'); + return ( + <> +

{t('title')}

+ {children} + + ); +} diff --git a/src/app/[locale]/(default)/rules/(main)/loading.tsx b/src/app/[locale]/(default)/rules/(main)/loading.tsx new file mode 100644 index 00000000..f430e757 --- /dev/null +++ b/src/app/[locale]/(default)/rules/(main)/loading.tsx @@ -0,0 +1,9 @@ +import { RuleCardListSkeleton } from '@/components/rules/RuleCardListSkeleton'; + +export default function RulesSkeleton() { + return ( +
+ +
+ ); +} diff --git a/src/app/[locale]/(default)/rules/(main)/page.tsx b/src/app/[locale]/(default)/rules/(main)/page.tsx new file mode 100644 index 00000000..1e4eeb24 --- /dev/null +++ b/src/app/[locale]/(default)/rules/(main)/page.tsx @@ -0,0 +1,64 @@ +import { RuleCard } from '@/components/rules/RuleCard'; +import { rulesMockdata as rules } from '@/mock-data/rules'; +import { getTranslations, setRequestLocale } from 'next-intl/server'; + +export async function generateMetadata({ + params, +}: { + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + + const t = await getTranslations({ locale, namespace: 'layout' }); + + return { + title: t('rules'), + }; +} + +export default async function RulesPage({ + params, +}: { + params: Promise<{ locale: string }>; +}) { + const { locale } = await params; + + setRequestLocale(locale); + const internal = rules.filter((rule) => rule.internal); + const notInternal = rules.filter((rule) => !rule.internal); + const t = await getTranslations('rules'); + const isMember = false; + + return ( +
+
+

+ {t('forEveryone')} +

+ {notInternal.map((rule) => ( + + ))} +
+
+

{t('internal')}

+ {internal.map((rule) => ( + + ))} +
+
+ ); +} diff --git a/src/app/[locale]/(default)/rules/[subset]/page.tsx b/src/app/[locale]/(default)/rules/[subset]/page.tsx new file mode 100644 index 00000000..26d72b5a --- /dev/null +++ b/src/app/[locale]/(default)/rules/[subset]/page.tsx @@ -0,0 +1,17 @@ +import { rulesMockdata } from '@/mock-data/rules'; +import { setRequestLocale } from 'next-intl/server'; +import { notFound } from 'next/navigation'; + +export default async function RuleSubSetPage({ + params, +}: { + params: Promise<{ locale: string; subset: string }>; +}) { + const { locale, subset } = await params; + setRequestLocale(locale); + const page = rulesMockdata.find( + (rule) => rule.id === Number.parseInt(subset), + ); + if (!page) return notFound(); + return

{page.title}

; +} diff --git a/src/components/news/ArticleCard.tsx b/src/components/news/ArticleCard.tsx index 32a5a719..a47a5ac9 100644 --- a/src/components/news/ArticleCard.tsx +++ b/src/components/news/ArticleCard.tsx @@ -34,7 +34,7 @@ function ArticleCard({ params: { article: id }, }} > - + + + {internal ? ( + + {t('internal')} + + ) : ( + {title} + )} + + {title} + + + + ); +} + +export { RuleCard }; diff --git a/src/components/rules/RuleCardListSkeleton.tsx b/src/components/rules/RuleCardListSkeleton.tsx new file mode 100644 index 00000000..61e90da0 --- /dev/null +++ b/src/components/rules/RuleCardListSkeleton.tsx @@ -0,0 +1,14 @@ +import { RuleCardSkeleton } from '@/components/rules/RuleCardSkeleton'; +import { useId } from 'react'; + +function RuleCardListSkeleton() { + return ( +
+ {Array.from({ length: 5 }).map(() => ( + + ))} +
+ ); +} + +export { RuleCardListSkeleton }; diff --git a/src/components/rules/RuleCardSkeleton.tsx b/src/components/rules/RuleCardSkeleton.tsx new file mode 100644 index 00000000..ad06cdf3 --- /dev/null +++ b/src/components/rules/RuleCardSkeleton.tsx @@ -0,0 +1,17 @@ +import { Button } from '@/components/ui/Button'; +import { Card, CardTitle } from '@/components/ui/Card'; +import { Skeleton } from '@/components/ui/Skeleton'; +import { cx } from '@/lib/utils'; + +function RuleCardSkeleton() { + return ( + + + + + + + ); +} + +export { RuleCardSkeleton }; diff --git a/src/lib/locale/index.ts b/src/lib/locale/index.ts index 861cd5c9..c2cf3bed 100644 --- a/src/lib/locale/index.ts +++ b/src/lib/locale/index.ts @@ -70,6 +70,14 @@ const routing = defineRouting({ en: '/storage/shopping-cart', no: '/lager/handlekurv', }, + '/rules': { + en: '/rules', + no: '/regler', + }, + '/rules/[subset]': { + en: '/rules/[subset]', + no: '/regler/[subset]', + }, '/shift-schedule': { en: '/shift-schedule', no: '/vaktliste', diff --git a/src/mock-data/rules.ts b/src/mock-data/rules.ts new file mode 100644 index 00000000..d34d1259 --- /dev/null +++ b/src/mock-data/rules.ts @@ -0,0 +1,90 @@ +const rulesMockdata = [ + { + id: 1, + internal: true, + title: 'Regler for regler', + photoUrl: 'mock.jpg', + content: + 'Reglene eksisterer av en grunn, overhold dem! • For din egen sikkerhet, andre sin sikkerhet og for at utstyr skal vare. • Regler håndheves av LabOps, Styret og Ledelsen • Si ifra hvis du ser regelbrudd. Ta ansvar. • Hvis du ikke vil si ifra selv, kan du gå via tillitsvalgt, som har taushetsplikt • Hvis reglene ikke følges, kan det føre til at man ikke får bruke utstyret, eller at man blir utestengt. • Regler kan foreslås endret og/eller fremlegges av hvem som helst, men godkjennes av styret.', + }, + { + id: 2, + internal: true, + title: 'Etiske retningslinjer', + photoUrl: 'mock.jpg', + }, + { + id: 3, + internal: false, + title: 'Regler for verkstedet', + photoUrl: 'mock.jpg', + }, + { + id: 4, + internal: true, + title: 'Regler for vakt', + photoUrl: 'mock.jpg', + }, + { + id: 5, + internal: false, + title: 'Regler for bruk av 3D-printer', + photoUrl: 'mock.jpg', + }, + { + id: 6, + internal: true, + title: 'Regler for kaffemaskin', + photoUrl: 'mock.jpg', + }, + { + id: 7, + internal: true, + title: 'Regler for utlån', + photoUrl: 'mock.jpg', + }, + { + id: 8, + internal: true, + title: 'Regler for kurs', + photoUrl: 'mock.jpg', + }, + { + id: 9, + internal: true, + title: 'Regler for arrangement', + photoUrl: 'mock.jpg', + }, + { + id: 10, + internal: false, + title: 'Regler for VR briller', + photoUrl: 'mock.jpg', + }, + { + id: 11, + internal: false, + title: 'Regler for verksted-PC', + photoUrl: 'mock.jpg', + }, + { + id: 12, + internal: true, + title: 'Regler for kjøkkenet', + photoUrl: 'mock.jpg', + }, + { + id: 13, + internal: false, + title: 'Regler for loddestasjon', + photoUrl: 'mock.jpg', + }, + { + id: 14, + internal: true, + title: 'Regler for Drive', + photoUrl: 'mock.jpg', + }, +]; + +export { rulesMockdata };