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 7 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 @@ -29,6 +29,7 @@
"events": "Events",
"storage": "Storage",
"about": "About",
"rules": "Rules",
"changeLocale": "Change language",
"toggleTheme": "Toggle theme",
"light": "Light",
Expand Down Expand Up @@ -123,5 +124,10 @@
"returnByDescription": "Select how long you would like to borrow the item for.",
"submit": "Submit"
}
},
"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 @@ -29,6 +29,7 @@
"events": "Hendelser",
"storage": "Lager",
"about": "Om oss",
"rules": "Rules",
"changeLocale": "Bytt språk",
"toggleTheme": "Bytt tema",
"light": "Lys",
Expand Down Expand Up @@ -123,5 +124,10 @@
"returnByDescription": "Velg hvor lenge du ønsker å låne gjenstanden(e)",
"submit": "Send"
}
},
"rules": {
"title": "Regler",
"forEveryone": "For alle ",
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
"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 { useTranslations } from 'next-intl';
import { unstable_setRequestLocale } from 'next-intl/server';

type RulesLayoutProps = {
children: React.ReactNode;
params: { locale: string };
};

export default function RulesLayout({
children,
params: { locale },
}: RulesLayoutProps) {
unstable_setRequestLocale(locale);
const t = useTranslations('rules');
return (
<>
<h1 className='text-center'>{t('title')}</h1>
{children}
</>
);
}
9 changes: 9 additions & 0 deletions src/app/[locale]/(default)/rules/(main)/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { RuleCardListSkeleton } from '@/components/rules/RuleCardListSkeleton';

export default function RulesSkeleton() {
return (
<>
<RuleCardListSkeleton />
</>
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
);
}
28 changes: 28 additions & 0 deletions src/app/[locale]/(default)/rules/(main)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { RuleCardList } from '@/components/rules/RuleCardList';
import { rulesMockdata } from '@/mock-data/rules';
import { getTranslations, unstable_setRequestLocale } from 'next-intl/server';
import { Suspense } from 'react';

export async function generateMetadata({
params: { locale },
}: {
params: { locale: string };
}) {
const t = await getTranslations({ locale, namespace: 'layout' });
return {
title: t('rules'),
};
}

export default function RulesPage({
params: { locale },
}: {
params: { locale: string };
}) {
unstable_setRequestLocale(locale);
return (
<>
<RuleCardList className='p4' rules={rulesMockdata} />
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
</>
);
}
14 changes: 14 additions & 0 deletions src/app/[locale]/(default)/rules/[subset]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { rulesMockdata } from '@/mock-data/rules';
import { unstable_setRequestLocale } from 'next-intl/server';
import { notFound } from 'next/navigation';

export default function RuleSubSetPage({
params: { subset },
}: { params: { subset: string } }) {
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
unstable_setRequestLocale(subset);
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
const page = rulesMockdata.find(
(rule) => rule.id === Number.parseInt(subset),
);
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 };
60 changes: 60 additions & 0 deletions src/components/rules/RuleCardList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
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 md:flex-nowrap md:space-x-5'>
<div
className={cx(
'xs:w-full sm:w-full',
isMember ? ' md:w-1/2' : 'md:full mt-5',
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
)}
>
<h2 className={cx(isMember ? 'border-b-0 p-4 text-center' : 'hidden')}>
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
{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={cx(isMember ? 'w-full md:w-1/2' : 'hidden')}>
MoaKK marked this conversation as resolved.
Show resolved Hide resolved
<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 @@ -37,5 +37,13 @@ export const routing = defineRouting({
en: '/storage/shopping-cart',
no: '/lager/handlekurv',
},
'/rules': {
en: '/rules',
no: '/regler',
},
'/rules/[subset]': {
en: '/rules/[subset]',
no: '/regler/[subset]',
},
},
});
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 };