1
0
Fork 0

feat: add /trainings page

- list of trainings
- add button (taken from github: vojtechmares/website)
- add currency formatter
This commit is contained in:
Vojtěch Mareš 2023-06-25 17:06:17 +02:00
parent 40b68902f7
commit 623b018a1b
Signed by: vojtech.mares
GPG key ID: C6827B976F17240D
3 changed files with 201 additions and 0 deletions

View file

@ -0,0 +1,9 @@
export function formatCurrency(price: number | bigint, locale: string = 'en-US', currency: string = 'CZK'): string {
const currencyFormatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency: currency,
maximumFractionDigits: 0,
});
return currencyFormatter.format(price).replace(',', ' ')
}

78
src/components/Button.tsx Normal file
View file

@ -0,0 +1,78 @@
import Link from "next/link";
import { ReactNode } from "react";
function classNames(...classes: any) {
return classes.filter(Boolean).join(' ')
}
const baseStyles = {
solid:
"group inline-flex items-center justify-center rounded-md font-semibold focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2",
outline:
"group inline-flex ring-1 items-center justify-center rounded-md focus:outline-none",
};
const variantStyles = {
solid: {
black:
"bg-black text-white hover:bg-gray-700 active:bg-gray-800 focus-visible:outline-gray-900",
amber:
"bg-amber-500 text-white hover:bg-amber-600 active:bg-amber-800 focus-visible:outline-amber-500",
white:
"bg-white text-black hover:bg-amber-50 active:bg-amber-200 focus-visible:outline-white",
},
outline: {
black:
"ring-gray-200 text-black hover:ring-gray-300 active:bg-gray-100 focus-visible:outline-amber-500 focus-visible:ring-gray-300",
white:
"ring-gray-700 text-white hover:ring-gray-500 active:ring-gray-700 focus-visible:outline-white",
amber: "", // Outline buttons cannot be amber
},
};
const transitionStyle = "transition duration-150 ease-in-out";
const sizeStyles = {
medium: "px-4 py-2 text-sm",
large: "px-8 py-4 text-base",
};
type Props = {
variant?: "solid" | "outline";
color?: "black" | "white" | "amber";
size?: "medium" | "large";
className?: string;
href?: string;
children?: ReactNode;
};
export function Button({
variant = "solid",
color = "black",
size = "medium",
className,
href,
children,
}: Props) {
if (variant === "outline" && color === "amber") {
throw new Error("Outline buttons cannot be amber");
}
className = classNames(
baseStyles[variant],
variantStyles[variant][color],
sizeStyles[size],
transitionStyle,
className
);
if (href !== undefined) {
return (
<Link href={href} className={className}>
{children}
</Link>
);
} else {
return <button className={className}>{children}</button>;
}
}

114
src/pages/trainings.tsx Normal file
View file

@ -0,0 +1,114 @@
import { GetServerSideProps } from "next";
import Head from "next/head";
import Link from "next/link";
import { formatCurrency } from "~/lib/currency/formatter";
import { prisma } from "~/server/db";
import { Training } from "lib/content/training";
import { Layout } from "~/components/Layout";
import { Button } from "~/components/Button";
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
const trainings = await prisma.training.findMany({
select: {
id: true,
name: true,
days: true,
draft: true,
priceOpen: true,
priceCorporate: true,
}
});
return { props: { trainings: trainings } };
}
function Table({trainings}: { trainings: Training[] }) {
return (
<div className="px-4 sm:px-6 lg:px-8">
<div className="sm:flex sm:items-center">
<div className="sm:flex-auto">
<h1 className="text-base font-semibold leading-6 text-gray-900">Trainings</h1>
{/* <p className="mt-2 text-sm text-gray-700">
A list of all the users in your account including their name, title, email and role.
</p> */}
</div>
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
{/* <button
type="button"
className="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Add user
</button> */}
<Button href="https://github.com/vojtechmares/backoffice/new/main/content/training">
Add training
</Button>
</div>
</div>
<div className="mt-8 flow-root">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Name
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Days
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Draft
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Price Open
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Price Corporate
</th>
<th scope="col" className="relative py-3.5 pl-3 pr-4 sm:pr-6">
<span className="sr-only">Edit</span>
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{trainings.map((training) => (
<tr key={training.id}>
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">
{training.name}
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{training.days}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{training.draft ? 'Yes' : 'No'}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{formatCurrency(training.priceOpen)}</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">{formatCurrency(training.priceCorporate)}</td>
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<Link href={"/trainings/" + training.id} className="text-black underline">
Detail<span className="sr-only"> of {training.name}</span>
</Link>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)
}
export default function Training({ trainings }: { trainings: Training[] }) {
return (
<>
<Head>
<title>Training | MaresHQ backoffice</title>
</Head>
<Layout>
{/* { JSON.stringify(trainings) } */}
<Table trainings={trainings} />
</Layout>
</>
);
}