Skip to content

Commit

Permalink
feat: add ability to add school as a chapter
Browse files Browse the repository at this point in the history
  • Loading branch information
iperalta7 committed Sep 25, 2024
1 parent 6b802b5 commit 795dfeb
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {
type ActionFunctionArgs,
json,
type LoaderFunctionArgs,
redirect,
} from '@remix-run/node';
import {
Form as RemixForm,
useActionData,
useLoaderData,
} from '@remix-run/react';

import { createChapter } from '@oyster/core/chapter';
import { getSchool } from '@oyster/core/education';
import { Button, Modal } from '@oyster/ui';

import { Route } from '@/shared/constants';
import {
commitSession,
ensureUserAuthenticated,
toast,
} from '@/shared/session.server';

export async function loader({ params, request }: LoaderFunctionArgs) {
await ensureUserAuthenticated(request);

const school = await getSchool({
select: ['name'],
where: { id: params.id as string },
});

if (!school) {
throw new Response(null, { status: 404 });
}

return json({
school,
});
}

export async function action({ params, request }: ActionFunctionArgs) {
const session = await ensureUserAuthenticated(request);

await createChapter({
schoolId: params.id as string,
});

toast(session, {
message: 'Created chapter.',
});

return redirect(Route['/schools'], {
headers: {
'Set-Cookie': await commitSession(session),
},
});
}

export default function CreateChapterModal() {
const { school } = useLoaderData<typeof loader>();

useActionData<typeof action>();

return (
<Modal onCloseTo={Route['/schools']}>
<Modal.Header>
<Modal.Title>Activate Chapter for {school.name}</Modal.Title>
<Modal.CloseButton />
</Modal.Header>

<Modal.Description>
Are you sure you want to create a chapter for {school.name}?
</Modal.Description>

<RemixForm className="form" method="post">
<Button.Group>
<Button.Submit>Create chapter</Button.Submit>
</Button.Group>
</RemixForm>
</Modal>
);
}
23 changes: 22 additions & 1 deletion apps/admin-dashboard/app/routes/_dashboard.schools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { Link, Outlet, useLoaderData } from '@remix-run/react';
import { sql } from 'kysely';
import { useState } from 'react';
import { Edit, Menu, Plus } from 'react-feather';
import { BookOpen, Edit, Menu, Plus } from 'react-feather';
import { generatePath } from 'react-router';
import { match } from 'ts-pattern';

Expand Down Expand Up @@ -40,10 +40,12 @@ export async function loader({ request }: LoaderFunctionArgs) {
);

const { schools, totalSchools } = await listSchools(searchParams);
const chapters = (await listChapters()).map((row) => row.schoolId);

return json({
schools,
totalSchools,
chapters,
});
}

Expand Down Expand Up @@ -91,6 +93,13 @@ async function listSchools({ limit, page, search }: ListSearchParams) {
};
}

// generate a list of ids of schools that have chapters
async function listChapters() {
const chapters = db.selectFrom(['chapters']).select(['schoolId']).execute();

return await chapters;
}

export async function action({ request }: ActionFunctionArgs) {
await ensureUserAuthenticated(request);

Expand Down Expand Up @@ -230,6 +239,7 @@ function SchoolsPagination() {

function SchoolsTableDropdown({ id }: SchoolInView) {
const [open, setOpen] = useState<boolean>(false);
const chapters = useLoaderData<typeof loader>().chapters;

function onClose() {
setOpen(false);
Expand All @@ -249,6 +259,17 @@ function SchoolsTableDropdown({ id }: SchoolInView) {
<Edit /> Edit School
</Link>
</Dropdown.Item>
{chapters.includes(id) ? null : (
<Dropdown.Item>
<Link
to={generatePath(Route['/schools/:id/chapter/create'], {
id,
})}
>
<BookOpen /> Create Chapter
</Link>
</Dropdown.Item>
)}
</Dropdown.List>
</Table.Dropdown>
)}
Expand Down
1 change: 1 addition & 0 deletions apps/admin-dashboard/app/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const ROUTES = [
'/schools',
'/schools/create',
'/schools/:id/edit',
'/schools/:id/chapter/create',
'/students',
'/students/import/programs',
'/students/import/resources',
Expand Down
2 changes: 2 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"./applications": "./src/modules/application/application.core.ts",
"./applications/types": "./src/modules/application/application.types.ts",
"./applications/ui": "./src/modules/application/application.ui.tsx",
"./chapter": "./src/modules/chapter/chapter.core.ts",
"./chapter/types": "./src/modules/chapter/chapter.types.ts",
"./education": "./src/modules/education/education.core.ts",
"./education/types": "./src/modules/education/education.types.ts",
"./education/ui": "./src/modules/education/education.ui.tsx",
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/modules/chapter/chapter.core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { db } from '@oyster/db';

import { type CreateChapterInput } from '@/modules/chapter/chapter.types';

// Add chapter
export async function createChapter({ schoolId }: CreateChapterInput) {
await db.insertInto('chapters').values({ schoolId }).execute();
}
20 changes: 20 additions & 0 deletions packages/core/src/modules/chapter/chapter.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { z } from 'zod';

import { Entity } from '@oyster/types';

// schema

export const Chapter = Entity.extend({
createdAt: z.date(),
schoolId: z.string(),
});

// Use Cases

export const CreateChapterInput = Chapter.pick({
schoolId: true,
});

//Types

export type CreateChapterInput = z.infer<typeof CreateChapterInput>;

0 comments on commit 795dfeb

Please sign in to comment.