Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rules page #60

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified bun.lockb
Binary file not shown.
6 changes: 6 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"storage": "Storage",
"about": "About",
"shiftSchedule": "Shift Schedule",
"rules": "Rules",
"changeLocale": "Change language",
"toggleTheme": "Toggle theme",
"light": "Light",
Expand Down Expand Up @@ -156,5 +157,10 @@
}
}
}
},
"rules": {
"title": "Rules",
"forEveryone": "For everyone",
"internal": "Internal rules"
}
}
6 changes: 6 additions & 0 deletions messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"storage": "Lager",
"about": "Om oss",
"shiftSchedule": "Vaktliste",
"rules": "Rules",
"changeLocale": "Bytt språk",
"toggleTheme": "Bytt tema",
"light": "Lys",
Expand Down Expand Up @@ -156,5 +157,10 @@
}
}
}
},
"rules": {
"title": "Regler",
"forEveryone": "For alle",
"internal": "Interne regler"
}
}
21 changes: 21 additions & 0 deletions src/app/[locale]/(default)/rules/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<h1 className='text-center'>{t('title')}</h1>
{children}
</>
);
}
5 changes: 5 additions & 0 deletions src/app/[locale]/(default)/rules/(main)/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { RuleCardListSkeleton } from '@/components/rules/RuleCardListSkeleton';

export default function RulesSkeleton() {
return <RuleCardListSkeleton />;
}
29 changes: 29 additions & 0 deletions src/app/[locale]/(default)/rules/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { RuleCardList } from '@/components/rules/RuleCardList';
import { rulesMockdata } 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);

return <RuleCardList rules={rulesMockdata} />;
}
17 changes: 17 additions & 0 deletions src/app/[locale]/(default)/rules/[subset]/page.tsx
Original file line number Diff line number Diff line change
@@ -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 }>;
}) {
const { locale } = await params;
setRequestLocale(locale);
const page = rulesMockdata.find(
(rule) => rule.id === Number.parseInt(locale),
);
if (!page) return notFound();
return <h1 className='text-center'>{page.title}</h1>;
}
57 changes: 57 additions & 0 deletions src/components/rules/RuleCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/Button';
import { Card, CardTitle } from '@/components/ui/Card';
import { Link } from '@/lib/locale/navigation';
import { cx } from '@/lib/utils';
import { useTranslations } from 'next-intl';
import Image from 'next/image';

type RuleCardProps = {
className?: string;
id: number;
internal: boolean;
title: string;
photoUrl: string;
};

function RuleCard({ className, id, internal, title, photoUrl }: RuleCardProps) {
const t = useTranslations('rules');

return (
<Button
className={cx('group whitespace-normal font-normal ring-0', className)}
asChild
variant='none'
size='none'
>
<Link
href={{
pathname: '/rules/[subset]',
params: { subset: id },
}}
aria-label={title}
>
<Card className='flex size-full transform overflow-hidden rounded-xl brightness-95 transition delay-150 duration-300 ease-in-out hover:scale-105 hover:border-primary hover:shadow-lg hover:brightness-100 dark:brightness-100 hover:dark:brightness-110'>
{internal ? (
<Badge className='flex w-1/3 items-center justify-center rounded-none text-lg hover:bg-primary '>
{t('internal')}
</Badge>
) : (
<Image
className='flex w-1/3 rounded-none'
src={`/${photoUrl}`}
alt={title}
width={150}
height={150}
/>
)}
<CardTitle className='flex w-2/3 items-center justify-center text-center text-lg sm:text-xl lg:text-2xl'>
{title}
</CardTitle>
</Card>
</Link>
</Button>
);
}

export { RuleCard };
55 changes: 55 additions & 0 deletions src/components/rules/RuleCardList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { RuleCard } from '@/components/rules/RuleCard';
import { cx } from '@/lib/utils';
import { useTranslations } from 'next-intl';

type RuleCardListProps = {
className?: string;
rules: Array<{
id: number;
internal: boolean;
title: string;
photoUrl: string;
}>;
};

function RuleCardList({ rules }: RuleCardListProps) {
const internal = rules.filter((rule) => rule.internal);
const notInternal = rules.filter((rule) => !rule.internal);
const t = useTranslations('rules');
const isMember = true;

return (
<div className='flex shrink flex-wrap justify-center p-4 md:flex-nowrap md:space-x-5'>
<div className={isMember ? ' md:w-1/2' : 'md:full mt-5'}>
<h2 className={isMember ? 'border-b-0 p-4 text-center' : 'hidden'}>
{t('forEveryone')}
</h2>
{notInternal.map((rule) => (
<RuleCard
className='mx-auto mb-3 flex max-w-2xl'
key={rule.id}
id={rule.id}
internal={rule.internal}
title={rule.title}
photoUrl={rule.photoUrl}
/>
))}
</div>
<div className={isMember ? 'w-full md:w-1/2' : 'hidden'}>
<h2 className='border-b-0 p-4 text-center'>{t('internal')}</h2>
{internal.map((rule) => (
<RuleCard
className='mb-3 flex h-16 max-w-2xl'
key={rule.id}
id={rule.id}
internal={rule.internal}
title={rule.title}
photoUrl={rule.photoUrl}
/>
))}
</div>
</div>
);
}

export { RuleCardList };
14 changes: 14 additions & 0 deletions src/components/rules/RuleCardListSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { RuleCardSkeleton } from '@/components/rules/RuleCardSkeleton';
import { useId } from 'react';

function RuleCardListSkeleton() {
return (
<div className='mt-5 flex size-full flex-col items-center justify-center'>
{Array.from({ length: 5 }).map(() => (
<RuleCardSkeleton key={useId()} />
))}
</div>
);
}

export { RuleCardListSkeleton };
24 changes: 24 additions & 0 deletions src/components/rules/RuleCardSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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 (
<Button
className={cx('group whitespace-normal font-normal ring-0')}
asChild
variant='none'
size='none'
>
<Card className='mb-3 h-[68px] w-full max-w-[614px] shrink transform overflow-hidden rounded-xl brightness-95 transition delay-150 duration-300 ease-in-out hover:scale-105 hover:border-primary hover:shadow-lg hover:brightness-100 md:h-[138px] dark:brightness-100 hover:dark:brightness-110'>
<Skeleton className='h-full w-1/3 rounded-none' />
<CardTitle className='flex h-full w-2/3 items-center justify-center'>
<Skeleton className='h-4 w-full max-w-24 rounded-full sm:max-w-48 md:h-7' />
</CardTitle>
</Card>
</Button>
);
}

export { RuleCardSkeleton };
8 changes: 8 additions & 0 deletions src/lib/locale/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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',
Expand Down
90 changes: 90 additions & 0 deletions src/mock-data/rules.ts
Original file line number Diff line number Diff line change
@@ -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 };
Loading