chore: user router types

This commit is contained in:
Henry
2024-07-24 15:39:14 +01:00
parent eff5654492
commit e50991f72f
11 changed files with 130 additions and 315 deletions

View File

@@ -0,0 +1,34 @@
const PatternedBackground = () => (
<div>
<svg
style={{
position: "absolute",
width: "100%",
height: "100%",
top: "0px",
left: "0px",
color: "white",
}}
>
<pattern
id="pattern"
x="0.034759358288862785"
y="3.335370511841166"
width="14.423223834988539"
height="14.423223834988539"
patternUnits="userSpaceOnUse"
patternTransform="translate(-0.45072574484339184,-0.45072574484339184)"
>
<circle
cx="0.45072574484339184"
cy="0.45072574484339184"
r="0.45072574484339184"
fill="#3e3e3e"
></circle>
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill="url(#pattern)"></rect>
</svg>
</div>
);
export default PatternedBackground;

View File

@@ -7,68 +7,26 @@ import React, {
import { api } from "~/utils/api";
import {
GetBoardByIdOutput,
ReorderCardInput,
ReorderListInput,
} from "~/types/router.types";
interface BoardContextProps {
boardData: BoardData;
setBoardData: React.Dispatch<React.SetStateAction<BoardData>>;
updateList: (params: UpdateListParams) => void;
updateCard: (params: UpdateCardParams) => void;
boardData: GetBoardByIdOutput;
setBoardData: React.Dispatch<React.SetStateAction<GetBoardByIdOutput>>;
updateList: (params: ReorderListInput) => void;
updateCard: (params: ReorderCardInput) => void;
}
interface BoardData {
name: string;
publicId: string;
labels: Label[];
lists: List[];
workspace: {
members: Members[];
} | null;
}
interface Label {
publicId: string;
name: string;
colourCode: string | null;
}
interface List {
publicId: string;
name: string;
boardId: number;
index: number;
cards: Card[];
}
interface Members {
publicId: string;
user: {
name: string | null;
} | null;
}
interface Card {
publicId: string;
title: string;
}
interface UpdateListParams {
boardId: string;
listId: string;
currentIndex: number;
newIndex: number;
}
interface UpdateCardParams {
cardId: string;
newListId: string;
newIndex: number;
}
const initialBoardData: BoardData = {
const initialBoardData: GetBoardByIdOutput = {
name: "",
publicId: "",
lists: [],
labels: [],
workspace: {
publicId: "",
members: [],
},
};
@@ -79,10 +37,13 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const utils = api.useUtils();
const [boardData, setBoardData] = useState<BoardData>(initialBoardData);
const [boardData, setBoardData] =
useState<GetBoardByIdOutput>(initialBoardData);
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
const refetchBoard = () => {
if (boardData?.publicId)
utils.board.byId.refetch({ boardPublicId: boardData.publicId });
};
const updateCardMutation = api.card.reorder.useMutation({
onSuccess: async () => {
@@ -109,7 +70,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
listId,
currentIndex,
newIndex,
}: UpdateListParams) => {
}: ReorderListInput) => {
updateListMutation.mutate({
boardId,
listId,
@@ -118,7 +79,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
});
};
const updateCard = ({ cardId, newListId, newIndex }: UpdateCardParams) => {
const updateCard = ({ cardId, newListId, newIndex }: ReorderCardInput) => {
updateCardMutation.mutate({
cardId,
newListId,

View File

@@ -69,56 +69,6 @@ export type Database = {
},
]
}
account: {
Row: {
access_token: string | null
expires_at: number | null
id_token: string | null
provider: string
providerAccountId: string
refresh_token: string | null
scope: string | null
session_state: string | null
token_type: string | null
type: string
userId: string
}
Insert: {
access_token?: string | null
expires_at?: number | null
id_token?: string | null
provider: string
providerAccountId: string
refresh_token?: string | null
scope?: string | null
session_state?: string | null
token_type?: string | null
type: string
userId: string
}
Update: {
access_token?: string | null
expires_at?: number | null
id_token?: string | null
provider?: string
providerAccountId?: string
refresh_token?: string | null
scope?: string | null
session_state?: string | null
token_type?: string | null
type?: string
userId?: string
}
Relationships: [
{
foreignKeyName: "account_userId_user_id_fk"
columns: ["userId"]
isOneToOne: false
referencedRelation: "user"
referencedColumns: ["id"]
},
]
}
board: {
Row: {
createdAt: string
@@ -425,32 +375,6 @@ export type Database = {
},
]
}
session: {
Row: {
expires: string
sessionToken: string
userId: string
}
Insert: {
expires: string
sessionToken: string
userId: string
}
Update: {
expires?: string
sessionToken?: string
userId?: string
}
Relationships: [
{
foreignKeyName: "session_userId_user_id_fk"
columns: ["userId"]
isOneToOne: false
referencedRelation: "user"
referencedColumns: ["id"]
},
]
}
user: {
Row: {
email: string
@@ -475,24 +399,6 @@ export type Database = {
}
Relationships: []
}
verificationToken: {
Row: {
expires: string
identifier: string
token: string
}
Insert: {
expires: string
identifier: string
token: string
}
Update: {
expires?: string
identifier?: string
token?: string
}
Relationships: []
}
workspace: {
Row: {
createdAt: string

View File

@@ -0,0 +1,9 @@
import { RouterInputs, type RouterOutputs } from "~/utils/api";
export type GetBoardByIdOutput = RouterOutputs["board"]["byId"];
export type ReorderListInput = RouterInputs["list"]["reorder"];
export type ReorderCardInput = RouterInputs["card"]["reorder"];
export type UpdateBoardInput = RouterInputs["board"]["update"];
export type NewListInput = RouterInputs["list"]["create"];
export type NewCardInput = RouterInputs["card"]["create"];
export type NewBoardInput = RouterInputs["board"]["create"];

View File

@@ -16,6 +16,13 @@ export function DeleteBoardConfirmation() {
},
});
const handleDeleteBoard = () => {
if (boardData?.publicId)
deleteBoard.mutate({
boardPublicId: boardData.publicId,
});
};
return (
<>
<div className="flex w-full flex-col justify-between pb-4">
@@ -34,11 +41,7 @@ export function DeleteBoardConfirmation() {
Cancel
</button>
<button
onClick={() =>
deleteBoard.mutate({
boardPublicId: boardData.publicId,
})
}
onClick={handleDeleteBoard}
className="inline-flex justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
>
Delete

View File

@@ -13,8 +13,10 @@ export function DeleteListConfirmation({
const { boardData } = useBoard();
const { closeModal } = useModal();
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
const refetchBoard = () => {
if (boardData?.publicId)
utils.board.byId.refetch({ boardPublicId: boardData.publicId });
};
const deleteList = api.list.delete.useMutation({
onSuccess: async () => {

View File

@@ -9,13 +9,11 @@ import CheckboxDropdown from "~/components/CheckboxDropdown";
import { useBoard } from "~/providers/board";
import { useModal } from "~/providers/modal";
interface FormData {
title: string;
listPublicId: string;
labelPublicIds: string[];
memberPublicIds: string[];
import { NewCardInput } from "~/types/router.types";
type NewCardFormInput = NewCardInput & {
isCreateAnotherEnabled: boolean;
}
};
interface NewCardFormProps {
listPublicId: string;
@@ -30,22 +28,25 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
const { boardData } = useBoard();
const { closeModal } = useModal();
const { register, handleSubmit, reset, setValue, watch } = useForm<FormData>({
defaultValues: {
title: "",
listPublicId,
labelPublicIds: [],
memberPublicIds: [],
isCreateAnotherEnabled: false,
},
});
const { register, handleSubmit, reset, setValue, watch } =
useForm<NewCardFormInput>({
defaultValues: {
title: "",
listPublicId,
labelPublicIds: [],
memberPublicIds: [],
isCreateAnotherEnabled: false,
},
});
const labelPublicIds = watch("labelPublicIds") || [];
const memberPublicIds = watch("memberPublicIds") || [];
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
const refetchBoard = () => {
if (boardData?.publicId)
utils.board.byId.refetch({ boardPublicId: boardData.publicId });
};
const createCard = api.card.create.useMutation({
onSuccess: async () => {
@@ -92,11 +93,11 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
selected: memberPublicIds.includes(member.publicId),
})) ?? [];
const onSubmit = (data: FormData) => {
const onSubmit = (data: NewCardInput) => {
createCard.mutate({
title: data.title,
listPublicId: data.listPublicId,
labelsPublicIds: data.labelPublicIds,
labelPublicIds: data.labelPublicIds,
memberPublicIds: data.memberPublicIds,
});
};

View File

@@ -7,28 +7,24 @@ import { Switch } from "@headlessui/react";
import { useBoard } from "~/providers/board";
import { useModal } from "~/providers/modal";
import { NewListInput } from "~/types/router.types";
import { Formik, Form, Field } from "formik";
interface FormValues {
name: string;
}
interface boardPublicId {
boardPublicId: string;
}
function classNames(...classes: string[]): string {
return classes.filter(Boolean).join(" ");
}
export function NewListForm({ boardPublicId }: boardPublicId) {
export function NewListForm({ boardPublicId }: { boardPublicId: string }) {
const utils = api.useUtils();
const { boardData } = useBoard();
const { closeModal } = useModal();
const [isCreateAnotherEnabled, setIsCreateAnotherEnabled] = useState(false);
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
const refetchBoard = () => {
if (boardData?.publicId)
utils.board.byId.refetch({ boardPublicId: boardData.publicId });
};
const createList = api.list.create.useMutation({
onSuccess: async () => {
@@ -64,8 +60,9 @@ export function NewListForm({ boardPublicId }: boardPublicId) {
<Formik
initialValues={{
name: "",
boardPublicId: "",
}}
onSubmit={(values: FormValues, { resetForm }) => {
onSubmit={(values: NewListInput, { resetForm }) => {
createList.mutate({
name: values.name,
boardPublicId,

View File

@@ -15,6 +15,7 @@ import { useBoard } from "~/providers/board";
import { useModal } from "~/providers/modal";
import Modal from "~/components/modal";
import PatternedBackground from "~/components/PatternedBackground";
import BoardDropdown from "./components/BoardDropdown";
import { DeleteBoardConfirmation } from "./components/DeleteBoardConfirmation";
@@ -24,38 +25,7 @@ import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { NewCardForm } from "./components/NewCardForm";
import { NewListForm } from "./components/NewListForm";
interface List {
publicId: string;
name: string;
cards?: Card[];
}
interface Card {
publicId: string;
title: string;
labels?: Label[];
members?: Member[];
}
interface Label {
publicId: string;
name: string;
colourCode: string;
}
interface Member {
publicId: string;
user: User;
}
interface User {
name: string;
}
interface FormValues {
boardId: string;
name: string;
}
import { UpdateBoardInput } from "~/types/router.types";
type PublicListId = string;
@@ -72,12 +42,12 @@ export default function BoardPage() {
const formik = useFormik({
initialValues: {
boardId: boardId ?? "",
boardPublicId: boardId ?? "",
name: boardData?.name ? boardData.name : "",
},
onSubmit: (values: FormValues) => {
onSubmit: (values: UpdateBoardInput) => {
updateBoard.mutate({
boardId: values.boardId,
boardPublicId: values.boardPublicId,
name: values.name,
});
},
@@ -85,7 +55,7 @@ export default function BoardPage() {
});
const { data, isSuccess, isLoading } = api.board.byId.useQuery(
{ id: boardId ?? "" },
{ boardPublicId: boardId ?? "" },
{
enabled: !!boardId,
},
@@ -95,7 +65,7 @@ export default function BoardPage() {
setBoardData(data);
}
if (!boardId) return <></>;
if (!boardId || !boardData) return <></>;
const openNewListForm = (publicBoardId: string) => {
openModal("NEW_LIST");
@@ -156,43 +126,7 @@ export default function BoardPage() {
return (
<div className="relative flex h-full flex-col">
<div>
<svg
style={{
position: "absolute",
width: "100%",
height: "100%",
top: "0px",
left: "0px",
color: "white",
}}
>
<pattern
id="pattern"
x="0.034759358288862785"
y="3.335370511841166"
width="14.423223834988539"
height="14.423223834988539"
patternUnits="userSpaceOnUse"
patternTransform="translate(-0.45072574484339184,-0.45072574484339184)"
>
<circle
cx="0.45072574484339184"
cy="0.45072574484339184"
r="0.45072574484339184"
fill="#3e3e3e"
></circle>
</pattern>
<rect
x="0"
y="0"
width="100%"
height="100%"
fill="url(#pattern)"
></rect>
</svg>
</div>
<PatternedBackground />
<div className="z-10 flex w-full justify-between p-8 ">
{isLoading ? (
<div className="flex space-x-2">
@@ -252,7 +186,7 @@ export default function BoardPage() {
{...provided.droppableProps}
>
<div className="min-w-[2rem]" />
{boardData?.lists?.map((list: List, index) => (
{boardData?.lists?.map((list, index) => (
<List
index={index}
key={index}
@@ -293,7 +227,9 @@ export default function BoardPage() {
className="inline-flex w-fit items-center gap-x-1.5 rounded-full px-2 py-1 text-[10px] font-medium text-neutral-600 ring-1 ring-inset ring-light-600 dark:text-dark-1000 dark:ring-dark-800"
>
<svg
fill={label.colourCode}
fill={
label.colourCode || undefined
}
className="h-2 w-2"
viewBox="0 0 6 6"
aria-hidden="true"
@@ -310,14 +246,15 @@ export default function BoardPage() {
className="inline-flex h-6 w-6 items-center justify-center rounded-full bg-light-900 ring-2 ring-light-50 dark:bg-gray-500 dark:ring-dark-500"
>
<span className="text-[10px] font-medium leading-none text-white">
{member.user.name
.split(" ")
.map((namePart) =>
namePart
.charAt(0)
.toUpperCase(),
)
.join("")}
{member?.user?.name &&
member.user.name
.split(" ")
.map((namePart) =>
namePart
.charAt(0)
.toUpperCase(),
)
.join("")}
</span>
</span>
))}

View File

@@ -2,6 +2,7 @@ import Link from "next/link";
import { api } from "~/utils/api";
import { useWorkspace } from "~/providers/workspace";
import PatternedBackground from "~/components/PatternedBackground";
export function BoardsList() {
const { workspace } = useWorkspace();
@@ -27,42 +28,7 @@ export function BoardsList() {
{data?.map((board) => (
<Link key={board.publicId} href={`boards/${board.publicId}`}>
<div className="align-center relative mr-5 flex h-[150px] w-full items-center justify-center rounded-md border border-dashed border-light-600 bg-light-50 shadow-sm hover:bg-light-200 dark:border-dark-600 dark:bg-dark-100 dark:hover:bg-dark-200">
<div>
<svg
style={{
position: "absolute",
width: "100%",
height: "100%",
top: "0px",
left: "0px",
color: "white",
}}
>
<pattern
id="pattern"
x="0.034759358288862785"
y="3.335370511841166"
width="14.423223834988539"
height="14.423223834988539"
patternUnits="userSpaceOnUse"
patternTransform="translate(-0.45072574484339184,-0.45072574484339184)"
>
<circle
cx="0.45072574484339184"
cy="0.45072574484339184"
r="0.45072574484339184"
fill="#3e3e3e"
></circle>
</pattern>
<rect
x="0"
y="0"
width="100%"
height="100%"
fill="url(#pattern)"
></rect>
</svg>
</div>
<PatternedBackground />
<p className="text-md px-4 font-medium text-neutral-900 dark:text-dark-1000">
{board.name}
</p>

View File

@@ -7,9 +7,7 @@ import { useWorkspace } from "~/providers/workspace";
import { Formik, Form, Field } from "formik";
interface FormValues {
name: string;
}
import { NewBoardInput } from "~/types/router.types";
export function NewBoardForm() {
const utils = api.useUtils();
@@ -40,8 +38,9 @@ export function NewBoardForm() {
<Formik
initialValues={{
name: "",
workspacePublicId: "",
}}
onSubmit={(values: FormValues) => {
onSubmit={(values: NewBoardInput) => {
createBoard.mutate({
name: values.name,
workspacePublicId: workspace?.publicId,