Skip to content

Commit

Permalink
Page creator v2 (CMS project) (#84)
Browse files Browse the repository at this point in the history
* add page stats

* improve add contributor flow

* update navbar links + fixes

* pages list init

* working pages list

* file organization

* add page deletion and creation flows
  • Loading branch information
hingobway authored Jul 2, 2024
1 parent 1459e2e commit e7f22f6
Show file tree
Hide file tree
Showing 27 changed files with 606 additions and 124 deletions.
6 changes: 3 additions & 3 deletions client/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions client/src/app/_components/_base/BooleanStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IconCheck, IconX } from '@tabler/icons-react';

import type { IconType } from '@/util/iconType';
import { clx } from '@/util/classConcat';

export default function BooleanStatus({
value,
className,
}: {
value: boolean;
className?: string;
}) {
const iconProps: Parameters<IconType>[0] = {
stroke: 1,
};
return (
<>
<div className={clx(className)} data-true={value || null}>
{value ? <IconCheck {...iconProps} /> : <IconX {...iconProps} />}
</div>
</>
);
}
11 changes: 4 additions & 7 deletions client/src/app/_components/nav/NavAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ import {
IconLogout,
IconTableOptions,
} from '@tabler/icons-react';
import { IconType } from '@/util/iconType';

import { useUser } from '@/app/_ctx/user/context';
import type { NavLinkType } from './_util/linksType';

const Links: {
href: string;
text: React.ReactNode;
icon?: IconType;
}[] = [
const links: NavLinkType[] = [
{
href: '/account',
text: 'Account Overview',
Expand Down Expand Up @@ -45,7 +42,7 @@ const NavAccount = () => {
{user && (
<Collapse in={isOpen}>
<div className="flex flex-col gap-2 p-4">
{Links.map(({ href, text, icon: Icon }, i) => (
{links.map(({ href, text, icon: Icon }, i) => (
<Link
key={i}
href={href}
Expand Down
32 changes: 19 additions & 13 deletions client/src/app/_components/nav/NavLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { AppShell, ScrollArea } from '@mantine/core';

import NavLink from './NavLink';
import type { NavLinkType } from './_util/linksType';

const links: NavLinkType[] = [
{ href: '/', text: 'Home' },
{ href: '/pages/instructions', text: 'Camp How-tos' },

{ href: '/calendar/new', text: 'Calendar - Add Stay' },
{ href: '/cms/pages', text: 'Pages' },

{ href: '#', text: <>&nbsp;</> },
{ href: '#', text: <>&nbsp;</> },
{ href: '#', text: <>&nbsp;</> },
{ href: '#', text: <>&nbsp;</> },
];

const NavLinks = () => {
return (
Expand All @@ -17,19 +31,11 @@ const NavLinks = () => {
)}
>
<div className="flex flex-col space-y-2 p-2">
<NavLink href="/">Home</NavLink>
<NavLink href="/test">Test</NavLink>
<NavLink href="/calendar/new">Calendar - Add stay</NavLink>
<NavLink href="/cms/page/new">Page creator</NavLink>

{Array(5)
.fill(0)
.map((_, i) => (
<div
className="h-10 rounded-full bg-emerald-900/80"
key={i}
></div>
))}
{links.map((it, i) => (
<NavLink key={i} href={it.href}>
{it.text}
</NavLink>
))}
</div>
</AppShell.Section>
</>
Expand Down
7 changes: 7 additions & 0 deletions client/src/app/_components/nav/_util/linksType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IconType } from '@/util/iconType';

export type NavLinkType = {
href: string;
text: React.ReactNode;
icon?: IconType;
};
37 changes: 0 additions & 37 deletions client/src/app/cms/page/new/page.tsx

This file was deleted.

File renamed without changes.
51 changes: 51 additions & 0 deletions client/src/app/cms/pages/_actions/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use server';

import { getUser } from '@/app/_ctx/user/provider';
import { graphError, graphql } from '@/query/graphql';
import { graphAuthServer } from '@/query/graphql.server';
import { ResultOf } from '@graphql-typed-document-node/core';

const NEW_CMS_PAGE = graphql(`
mutation CmsPageCreate(
$title: String!
$secure: Boolean!
$publish: Boolean!
$contributorAdd: String
) {
cmsPageCreate(
title: $title
secure: $secure
publish: $publish
contributorAdd: $contributorAdd
) {
id
}
}
`);
type CmsPageOut = ResultOf<typeof NEW_CMS_PAGE>['cmsPageCreate'];

export async function createNewPage() {
const output: { data: CmsPageOut | null; error: string | null } = {
data: null,
error: null,
};
try {
const user = (await getUser()) || null;

const data = await graphAuthServer(NEW_CMS_PAGE, {
title: '',
secure: true,
publish: false,
contributorAdd: user?.id,
}).catch((err) => {
throw graphError(err?.response?.errors);
});
if (!data?.cmsPageCreate) throw 'SERVER_ERROR';

output.data = data.cmsPageCreate;
} catch (error) {
output.error = (error as string) || null;
} finally {
return output;
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Placeholder from '@tiptap/extension-placeholder';

import { clx } from '@/util/classConcat';
import { useSkeleton } from '@/app/_ctx/skeleton/context';
import { EditFormProps } from './PageEditForm';
import { EditFormProps } from '../edit/[id]/_components/PageEditForm';
import { useEffect, useMemo } from 'react';
import { proseStyles } from '../../_util/proseStyles';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useSkeleton } from '@/app/_ctx/skeleton/context';

import A from '@/app/_components/_base/A';
import { EditFormProps } from './PageEditForm';
import { EditFormProps } from '../edit/[id]/_components/PageEditForm';

export default function ViewPageLink({ serverPage }: EditFormProps) {
const slug = serverPage?.slug ?? null;
Expand Down
37 changes: 37 additions & 0 deletions client/src/app/cms/pages/_components/home/NewPageButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useTransition } from 'react';

import { ActionIcon } from '@mantine/core';
import { IconPlus } from '@tabler/icons-react';
import { notifications } from '@mantine/notifications';

import { createNewPage } from '../../_actions/create';
import { revalidatePagesList } from './PagesContainer';

export default function NewPageButton() {
const [isLoading, loading] = useTransition();
function createPage() {
loading(async () => {
const { data, error } = await createNewPage();
if (error || !data) {
notifications.show({ message: 'An error occurred.' });
return;
}

revalidatePagesList();
});
}

return (
<>
<ActionIcon
onClick={createPage}
loading={isLoading}
color="slate"
variant="light"
size="sm"
>
<IconPlus />
</ActionIcon>
</>
);
}
58 changes: 58 additions & 0 deletions client/src/app/cms/pages/_components/home/PagesContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client';

import { queryClient, useGraphQuery } from '@/query/query';
import { graphql } from '@/query/graphql';
import type { ResultOf } from '@graphql-typed-document-node/core';

import { SkeletonProvider } from '@/app/_ctx/skeleton/context';
import PagesList from './PagesList';
import NewPageButton from './NewPageButton';

const GET_PAGES_QUERY = graphql(`
query CmsPages {
cmsPages {
id
slug
title
secure
publish
contributors {
id
}
timestamp {
created
updated
}
}
}
`);
export type PagesType = ResultOf<typeof GET_PAGES_QUERY>['cmsPages'];
export const revalidatePagesList = () =>
queryClient.invalidateQueries({ queryKey: [GET_PAGES_QUERY, {}] });

// COMPONENT
export default function PagesContainer() {
const pagesQuery = useGraphQuery(GET_PAGES_QUERY, {});
const pages = pagesQuery.data?.cmsPages ?? null;

return (
<>
<div className="mx-auto flex max-w-screen-xl flex-col gap-6 p-6">
<SkeletonProvider ready={!pagesQuery.isPending}>
<div className="t">
<h3 className="py-4 text-lg">Pages</h3>
<PagesList pages={pages} />
</div>

<div className="t">
<div className="flex flex-row items-center justify-between">
<h3 className="py-4 text-lg">Unused (empty) pages</h3>
<NewPageButton />
</div>
<PagesList pages={pages} unused />
</div>
</SkeletonProvider>
</div>
</>
);
}
Loading

0 comments on commit e7f22f6

Please sign in to comment.