Skip to content

Commit

Permalink
Merge pull request #31 from complexdatacollective/feature/example-use…
Browse files Browse the repository at this point in the history
…-optimistic

Next 14
  • Loading branch information
jthrilly authored Nov 1, 2023
2 parents ee8402f + a61aeda commit ab54e49
Show file tree
Hide file tree
Showing 47 changed files with 1,123 additions and 1,046 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ const config = {
argsIgnorePattern: '^_',
},
],
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": false
}
],
'no-unreachable': 'error',
'local-rules/require-data-mapper': 'error',
},
Expand Down
23 changes: 0 additions & 23 deletions app/(dashboard)/dashboard/_components/AnonymousRecruitment.tsx

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion app/(dashboard)/dashboard/_components/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function NavigationBar() {
const pathname = usePathname();

return (
<nav className="flex justify-between p-10">
<nav className="flex justify-between bg-[#e5e7eb] px-4 py-2">
<Link href="/" className="mr-6 flex items-center space-x-2">
<Image
src="/images/[email protected]"
Expand Down
36 changes: 7 additions & 29 deletions app/(dashboard)/dashboard/_components/ResetButton.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,13 @@
'use client';

import { Loader2 } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { api } from '~/trpc/client';
import { Button } from '~/components/ui/Button';
import { resetAppSettings } from '~/app/_actions';
import SubmitButton from '~/components/ui/SubmitButton';

const ResetButton = () => {
const [loading, setLoading] = useState(false);
const router = useRouter();
const { mutateAsync: resetConfigured } = api.appSettings.reset.useMutation({
onError(error) {
throw new Error(error.message);
},
});

const reset = async () => {
setLoading(true);
await resetConfigured();
router.refresh();
};

return (
<Button
variant="destructive"
onClick={() => void reset()}
disabled={loading}
>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Reset all app data
</Button>
<form action={resetAppSettings}>
<SubmitButton type="submit" variant="destructive">
Reset all app data
</SubmitButton>
</form>
);
};

Expand Down
20 changes: 3 additions & 17 deletions app/(dashboard)/dashboard/_components/UserMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
'use client';

import { Loader2 } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { api } from '~/trpc/client';
import { Button } from '~/components/ui/Button';
import { useSession } from '~/providers/SessionProvider';

const UserMenu = () => {
const { session } = useSession();
const router = useRouter();

const { mutate: doSignout, isLoading: isSigningOut } =
api.session.signOut.useMutation({
onSuccess: () => {
router.refresh();
},
onError: (err) => {
throw new Error(err.message);
},
});
const { signOut, isLoading } = useSession();

return (
<div className="flex flex-row items-center gap-6">
{session && <span>{session?.user.username}</span>}
<Button onClick={() => void doSignout()} disabled={isSigningOut}>
{isSigningOut && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
<Button onClick={() => void signOut()} disabled={isLoading}>
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Sign out
</Button>
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ResetButton from './_components/ResetButton';
import AnonymousRecruitment from './_components/AnonymousRecruitment';
import AnonymousRecruitmentSwitch from '~/components/AnonymousRecruitmentSwitch/AnonymousRecruitmentSwitch';
import Link from 'next/link';
import { Button } from '~/components/ui/Button';

Expand All @@ -13,7 +13,7 @@ function Home() {
<Button>Start anonymous interview</Button>
</Link>
<ResetButton />
<AnonymousRecruitment />
<AnonymousRecruitmentSwitch />
</main>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ function ParticipantModal({
onMutate() {
setIsLoading(true);
},
async onSuccess() {
await utils.participant.get.invalidate();
},
onError(error) {
setError(error.message);
},
Expand Down Expand Up @@ -112,9 +109,8 @@ function ParticipantModal({
await createParticipant([data.identifier]);
}

await utils.participant.get.invalidate();

if (!error) {
await utils.participant.get.invalidate();
setOpen(false);
reset();
}
Expand Down
23 changes: 7 additions & 16 deletions app/(dashboard)/dashboard/participants/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,13 @@ import { api } from '~/trpc/server';
export const dynamic = 'force-dynamic';

const ParticipantPage = async () => {
try {
const participants = await api.participant.get.all.query(undefined, {
context: {
revalidate: 0,
},
});

return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Participant management view</h2>
<ParticipantsTable initialData={participants} />
</div>
);
} catch (error) {
throw new Error('An error occurred while fetching participants');
}
const participants = await api.participant.get.all.query();
return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Participant management view</h2>
<ParticipantsTable initialData={participants} />
</div>
);
};

export default ParticipantPage;
24 changes: 8 additions & 16 deletions app/(dashboard)/dashboard/protocols/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import { ProtocolsTable } from '~/app/(dashboard)/dashboard/_components/ProtocolsTable/ProtocolsTable';
import { ProtocolsTable } from '../_components/ProtocolsTable/ProtocolsTable';
import { api } from '~/trpc/server';

const ProtocolsPage = async () => {
try {
const protocols = await api.protocol.get.all.query(undefined, {
context: {
revalidate: 0,
},
});
return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Protocols management view</h2>
<ProtocolsTable initialData={protocols} />
</div>
);
} catch (error) {
throw new Error('An error occurred while fetching protocols');
}
const protocols = await api.protocol.get.all.query();
return (
<div className="rounded-lg bg-white p-6">
<h2 className="mb-6 text-2xl font-bold">Protocols management view</h2>
<ProtocolsTable initialData={protocols} />
</div>
);
};

export default ProtocolsPage;
9 changes: 1 addition & 8 deletions app/(interview)/interview/[interviewId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@ export default async function Page({
return 'No interview id found';
}

const interview = await api.interview.get.byId.query(
{ id: interviewId },
{
context: {
revalidate: 0,
},
},
);
const interview = await api.interview.get.byId.query({ id: interviewId });

if (!interview) {
return 'No interview found';
Expand Down
9 changes: 2 additions & 7 deletions app/(interview)/interview/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,9 @@ export default async function Page({
);
}
// check if anonymous recruitment is enabled
const allowAnonymousRecruitment =
await api.appSettings.get.allowAnonymousRecruitment.query(undefined, {
context: {
revalidate: 0,
},
});
const appSettings = await api.appSettings.get.query();

if (!allowAnonymousRecruitment) {
if (!appSettings || !appSettings.allowAnonymousRecruitment) {
return (
<ErrorMessage
title="Anonymous Recruitment Disabled"
Expand Down
26 changes: 26 additions & 0 deletions app/(onboard)/_components/Helpers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { motion } from 'framer-motion';
import { Loader2 } from 'lucide-react';
import type { ReactNode } from 'react';

export const StepLoadingState = () => (
<motion.div
className="flex h-full min-w-[30rem] items-center justify-center"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<Loader2 className="h-8 w-8 animate-spin" />
</motion.div>
);

export const StepMotionWrapper = ({ children }: { children: ReactNode }) => {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
{children}
</motion.div>
);
};
22 changes: 9 additions & 13 deletions app/(onboard)/_components/OnboardSteps/CreateAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
'use client';

import type { Route } from 'next';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { SignUpForm } from '~/app/(onboard)/_components/SignUpForm';
import { useOnboardingContext } from '../OnboardingProvider';

function CreateAccount() {
const router = useRouter();
const pathname = usePathname() as Route;
const searchParams = useSearchParams();
const step = searchParams.get('step');
const { setCurrentStep } = useOnboardingContext();

const completeCallback = () => {
router.push(`${pathname}?step=${parseInt(step || '1') + 1}`);
setCurrentStep(2).catch(() => {});
};

return (
<div className="max-w-[30rem]">
<div className="w-[30rem]">
<div className="mb-4 flex flex-col">
<h1 className="text-3xl font-bold">Create an Account</h1>
<p className="mb-4 mt-4">
To use Fresco, you need to set up an administrator account which will
enable to you access the protect parts of the app. Only one
administrator account can be created.
</p>
</div>
<p className="mb-4 mt-4">
To use Fresco, you need to set up an administrator account which will
enable to you access the protect parts of the app. Only one
administrator account can be created.
</p>
<SignUpForm completeCallback={completeCallback} />
</div>
);
Expand Down
Loading

0 comments on commit ab54e49

Please sign in to comment.