Skip to content

Commit

Permalink
Merge pull request #146 from Apsysikal/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Apsysikal authored Dec 23, 2024
2 parents 1fd9030 + 68083b4 commit 7ac6ccd
Show file tree
Hide file tree
Showing 37 changed files with 481 additions and 189 deletions.
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
DATABASE_URL="file:./data.db?connection_limit=1"
SESSION_SECRET="super-duper-s3cret"
IMAGE_UPLOAD_FOLDER="/workspaces/mokupona/build/uploads"
3 changes: 1 addition & 2 deletions app/components/dinner-card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Event } from "@prisma/client";
import type { SerializeFrom } from "@remix-run/node";
import { Link } from "@remix-run/react";

import { Button } from "./ui/button";
Expand All @@ -10,7 +9,7 @@ export function DinnerCard({
event,
preferredLocale,
}: {
event: Event | SerializeFrom<Event>;
event: Event;
preferredLocale: string;
}) {
const parsedDate = new Date(event.date);
Expand Down
8 changes: 2 additions & 6 deletions app/components/dinner-view.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import type { Address, Event } from "@prisma/client";
import { SerializeFrom } from "@remix-run/node";

import { AutoLink } from "./auto-link";

import { loader } from "~/routes/admin.dinners.$dinnerId";
import { getEventImageUrl } from "~/utils/misc";

export interface DinnerViewProps {
event:
| (Event & { address: Address })
| SerializeFrom<Event & { address: Address }>;
event: Awaited<ReturnType<typeof loader>>["event"];
}

export function DinnerView({ event }: DinnerViewProps) {
Expand Down
14 changes: 7 additions & 7 deletions app/components/ui/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value;

const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {
className?: string | ClassValue[];
}
Expand All @@ -39,7 +39,7 @@ const SelectTrigger = React.forwardRef<
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;

const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton> & {
className?: string | ClassValue[];
}
Expand All @@ -58,7 +58,7 @@ const SelectScrollUpButton = React.forwardRef<
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;

const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton> & {
className?: string | ClassValue[];
}
Expand All @@ -78,7 +78,7 @@ SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName;

const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {
className?: string | ClassValue[];
position: "item-aligned" | "popper";
Expand Down Expand Up @@ -113,7 +113,7 @@ const SelectContent = React.forwardRef<
SelectContent.displayName = SelectPrimitive.Content.displayName;

const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label> & {
className?: string | ClassValue[];
}
Expand All @@ -127,7 +127,7 @@ const SelectLabel = React.forwardRef<
SelectLabel.displayName = SelectPrimitive.Label.displayName;

const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item> & {
className?: string | ClassValue[];
}
Expand All @@ -151,7 +151,7 @@ const SelectItem = React.forwardRef<
SelectItem.displayName = SelectPrimitive.Item.displayName;

const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator> & {
className?: string | ClassValue[];
}
Expand Down
14 changes: 5 additions & 9 deletions app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { HamburgerMenuIcon, InstagramLogoIcon } from "@radix-ui/react-icons";
import type {
LinksFunction,
LoaderFunctionArgs,
SerializeFrom,
} from "@remix-run/node";
import { json } from "@remix-run/node";
import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node";
import { data } from "@remix-run/node";
import {
Form,
Link,
Expand Down Expand Up @@ -36,7 +32,7 @@ import { getToast } from "./utils/toast.server";
import stylesheet from "~/tailwind.css?url";
import { getUserWithRole } from "~/utils/session.server";

export type RootLoaderData = SerializeFrom<typeof loader>;
export type RootLoaderData = typeof loader;

export const links: LinksFunction = () => [
{ rel: "stylesheet", href: stylesheet },
Expand Down Expand Up @@ -74,7 +70,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const domainUrl = getDomainUrl(request);
const user = await getUserWithRole(request);
const { toast, headers } = await getToast(request);
return json({ user, toast, domainUrl }, { headers: combineHeaders(headers) });
return data({ user, toast, domainUrl }, { headers: combineHeaders(headers) });
};

export default function App() {
Expand All @@ -86,7 +82,7 @@ export default function App() {
<Meta />
<Links />
</head>
<body className="h-full bg-gray-950 text-gray-50">
<body className="dark h-full bg-gray-950 text-gray-50">
<Document />
<ScrollRestoration />
<Scripts />
Expand Down
3 changes: 3 additions & 0 deletions app/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { flatRoutes } from "@remix-run/fs-routes";

export default flatRoutes();
4 changes: 2 additions & 2 deletions app/routes/admin._index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoaderFunctionArgs, MetaFunction, json } from "@remix-run/node";
import { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Link } from "@remix-run/react";

import { Button } from "~/components/ui/button";
Expand All @@ -7,7 +7,7 @@ import { requireUserWithRole } from "~/utils/session.server";

export async function loader({ request }: LoaderFunctionArgs) {
await requireUserWithRole(request, ["moderator", "admin"]);
return json({});
return {};
}

export const meta: MetaFunction<typeof loader> = () => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/admin.dinners.$dinnerId.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoaderFunctionArgs, MetaFunction, json } from "@remix-run/node";
import { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Form, Link, useLoaderData } from "@remix-run/react";
import invariant from "tiny-invariant";

Expand All @@ -17,7 +17,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) {

if (!event) throw new Response("Not found", { status: 404 });

return json({ event });
return { event };
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
Expand Down
62 changes: 18 additions & 44 deletions app/routes/admin.dinners.$dinnerId_.edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,25 @@ import {
useForm,
} from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { FileUpload, parseFormData } from "@mjackson/form-data-parser";
import {
ActionFunctionArgs,
LoaderFunctionArgs,
MaxPartSizeExceededError,
MetaFunction,
NodeOnDiskFile,
json,
redirect,
unstable_composeUploadHandlers,
unstable_createFileUploadHandler,
unstable_createMemoryUploadHandler,
unstable_parseMultipartFormData,
} from "@remix-run/node";
import { Form, useActionData, useLoaderData } from "@remix-run/react";
import invariant from "tiny-invariant";
import { z } from "zod";

import { Field, SelectField, TextareaField } from "~/components/forms";
import { Button } from "~/components/ui/button";
import { prisma } from "~/db.server";
import { getAddresses } from "~/models/address.server";
import { getEventById, updateEvent } from "~/models/event.server";
import {
fileStorage,
getStorageKey,
} from "~/utils/dinner-image-storage.server";
import { ClientEventSchema } from "~/utils/event-validation";
import { ServerEventSchema } from "~/utils/event-validation.server";
import { getTimezoneOffset, offsetDate } from "~/utils/misc";
Expand All @@ -46,11 +43,11 @@ export async function loader({ request, params }: LoaderFunctionArgs) {

if (!event) throw new Response("Not found", { status: 404 });

return json({
return {
validImageTypes,
addresses,
dinner: event,
});
};
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
Expand All @@ -71,41 +68,18 @@ export async function action({ request, params }: ActionFunctionArgs) {
const { dinnerId } = params;
invariant(typeof dinnerId === "string", "Parameter dinnerId is missing");

const uploadHandler = unstable_composeUploadHandlers(
unstable_createFileUploadHandler({
directory: process.env.IMAGE_UPLOAD_FOLDER,
}),
unstable_createMemoryUploadHandler(),
);
const uploadHandler = async (fileUpload: FileUpload) => {
let storageKey = getStorageKey("temporary-key");
await fileStorage.set(storageKey, fileUpload);
return fileStorage.get(storageKey);
};

const formData = await unstable_parseMultipartFormData(
request,
async (part) => {
try {
const result = await uploadHandler(part);
return result;
} catch (error) {
if (error instanceof MaxPartSizeExceededError) {
maximumFileSizeExceeded = true;
return new File([], "cover");
}
throw error;
}
},
);
const formData = await parseFormData(request, uploadHandler);

const submission = parseWithZod(formData, {
schema: (intent) =>
schema.superRefine((data, ctx) => {
schema.superRefine((data) => {
if (intent !== null) return { ...data };
if (maximumFileSizeExceeded) {
ctx.addIssue({
path: ["cover"],
code: z.ZodIssueCode.custom,
message: "File cannot be greater than 3MB",
});
return;
}
}),
});

Expand All @@ -116,11 +90,11 @@ export async function action({ request, params }: ActionFunctionArgs) {
) {
// Remove the uploaded file from disk.
// It will be sent again when submitting.
await (submission.payload.cover as unknown as NodeOnDiskFile).remove();
await fileStorage.remove(getStorageKey("temporary-key"));
}

if (submission.status !== "success" || !submission.value) {
return json(submission.reply());
return submission.reply();
}

const { title, description, date, slots, price, cover, addressId } =
Expand All @@ -138,7 +112,7 @@ export async function action({ request, params }: ActionFunctionArgs) {

// Remove the file from disk.
// It is in the database now.
await (cover as NodeOnDiskFile).remove();
await fileStorage.remove(getStorageKey("temporary-key"));
}

const event = await updateEvent(dinnerId, {
Expand Down Expand Up @@ -167,7 +141,7 @@ export default function DinnersPage() {
defaultValue: {
title: dinner.title,
description: dinner.description,
date: dinner.date.substring(0, 16),
date: dinner.date.toISOString().substring(0, 16),
slots: dinner.slots,
price: dinner.price,
addressId: dinner.addressId,
Expand Down
6 changes: 3 additions & 3 deletions app/routes/admin.dinners.$dinnerId_.signups.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoaderFunctionArgs, MetaFunction, json } from "@remix-run/node";
import { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import invariant from "tiny-invariant";

Expand Down Expand Up @@ -27,10 +27,10 @@ export async function loader({ request, params }: LoaderFunctionArgs) {

if (!event) throw new Response("Not found", { status: 404 });

return json({
return {
event,
responses,
});
};
}

export const meta: MetaFunction<typeof loader> = ({ data }) => {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/admin.dinners._index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoaderFunctionArgs, MetaFunction, json } from "@remix-run/node";
import { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Link, useFetcher, useLoaderData } from "@remix-run/react";

import { Button } from "~/components/ui/button";
Expand All @@ -9,7 +9,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
await requireUserWithRole(request, ["moderator", "admin"]);
const events = await getEvents();

return json({ events });
return { events };
}

export const meta: MetaFunction<typeof loader> = () => {
Expand Down
Loading

0 comments on commit 7ac6ccd

Please sign in to comment.