Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inv-126 : 타이틀, 내용 업데이트 쿼리 #64

Merged
merged 11 commits into from
Aug 18, 2024
4 changes: 2 additions & 2 deletions src/app/(main)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default async function Page() {
if (!auth.user) {
return redirect("/sign-in");
}
const invitations = await getInvitationsByUserId(auth.user.id);
const invitations = await getInvitationsByUserId();

return (
<div className="flex h-dvh flex-col overflow-hidden">
Expand Down Expand Up @@ -55,7 +55,7 @@ export default async function Page() {
{invitations.map((invitation) => (
<li key={invitation.id} className="h-full w-full">
<Link
href={`/i/${invitation.id}/edit`}
href={`/i/${invitation.eventUrl}/edit`}
className="flex h-full flex-col bg-muted p-0.5"
>
<div className="flex-1 overflow-hidden rounded-xl border border-border bg-background p-3">
Expand Down
57 changes: 15 additions & 42 deletions src/app/(main)/i/[subdomain]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,22 @@
import Editor from "~/components/editor";
import { getInvitationByEventUrl } from "~/lib/db/schema/invitations.query";

export default async function Page({
params,
}: {
params: { subdomain: string };
}) {
const invitation = await getInvitationByEventUrl(params.subdomain);

export default async function Page() {
return (
<Editor
editorConfig={{ backLink: "/pg" }}
editorData={[
{
id: "__body",
type: "__body",
name: "Body",
styles: {},
content: [
{
id: "container",
name: "Container",
type: "container",
styles: {
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 10,
paddingTop: 10,
paddingRight: 10,
paddingBottom: 10,
paddingLeft: 10,
width: "100%",
height: "auto",
},
content: [
{
id: "text",
name: "Text",
type: "text",
styles: {
textAlign: "left",
},
content: {
innerText: "Hello World",
},
},
],
},
],
},
]}
editorConfig={{
backLink: "/pg",
invitationId: invitation.id,
invitationTitle: invitation.title,
invitationSubdomain: invitation.eventUrl,
}}
editorData={invitation.customFields}
/>
);
}
24 changes: 24 additions & 0 deletions src/app/(main)/i/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Script from "next/script";
import { env } from "~/lib/env";

export default function KakaoMapScriptLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<>
<Script
strategy="beforeInteractive"
type="text/javascript"
src={`${env.DAUMCDN_POSTOCDE_URL}`}
/>
<Script
strategy="beforeInteractive"
type="text/javascript"
src={`${env.KAKAO_MAP_BASE_URL}?appkey=${env.KAKAO_MAP_API_KEY}&libraries=services&autoload=false`}
/>
{children}
</>
);
}
28 changes: 21 additions & 7 deletions src/components/editor/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Undo2,
} from "lucide-react";
import Link from "next/link";
import { useParams, useRouter } from "next/navigation";
import { toast } from "sonner";
import { useEditor } from "~/components/editor/provider";
import TitleInput from "~/components/editor/title-input";
Expand All @@ -27,11 +28,18 @@ import {
} from "~/components/ui/dropdown-menu";
import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs";
import TooltipSimple from "~/components/ui/tooltip-simple";
import {
deleteInvitation,
updateInvitation,
} from "~/lib/db/schema/invitations.query";
import { cn } from "~/lib/utils";

export default function EditorNavigation() {
const { editor, dispatch } = useEditor();
const router = useRouter();
const { openDialog } = useAlertDialogStore();
const params = useParams();
const subDomain = params.subdomain;

const handlePreviewClick = () => {
dispatch({ type: "TOGGLE_PREVIEW_MODE" });
Expand All @@ -47,14 +55,17 @@ export default function EditorNavigation() {

const handleOnSave = async () => {
try {
const content = JSON.stringify(editor.data);
console.log(":content", content);
// TODO: API insert page
// TODO: API log notification
toast.success("Saved Editor");
await updateInvitation({
id: editor.config.invitationId,
title: editor.config.invitationTitle,
customFields: editor.data,
});
toast.success("저장되었습니다.");
} catch (error) {
console.error(error);
toast.error("Oppse!", { description: "Could not save editor" });
toast.error("일시적인 오류가 발생되었습니다.", {
description: "잠시후 다시 시도해보세요.",
});
}
};

Expand All @@ -64,7 +75,10 @@ export default function EditorNavigation() {
description: "이 작업을 되돌릴 수 없습니다.",
confirmText: "확인",
cancelText: "취소",
onConfirm: () => {},
onConfirm: async () => {
await deleteInvitation(editor.config.invitationId);
router.replace("/dashboard");
},
});
};

Expand Down
20 changes: 13 additions & 7 deletions src/components/editor/title-input.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
"use client";

import { useMutation } from "@tanstack/react-query";
import { debounce, delay, random } from "es-toolkit";
import { debounce, delay } from "es-toolkit";
import { CheckIcon, LoaderIcon, XIcon } from "lucide-react";
import { useRef } from "react";
import { toast } from "sonner";
import { useEditor } from "~/components/editor/provider";
import { updateInvitation } from "~/lib/db/schema/invitations.query";
import { cn } from "~/lib/utils";

export default function TitleInput() {
const { editor } = useEditor();
const { editor, dispatch } = useEditor();

const abortControllerRef = useRef<AbortController | null>(null);

Expand Down Expand Up @@ -40,16 +41,21 @@ export default function TitleInput() {
value: string;
signal: AbortSignal;
}) => {
await delay(1000);

if (signal.aborted) {
return;
}

if (random(0, 1) > 0.5) {
throw new Error("Failed to update title");
}
await updateInvitation({
id: editor.config.invitationId,
title: value,
});

dispatch({
type: "UPDATE_CONFIG",
payload: {
invitationTitle: value,
},
});
delayMutation.mutate();
},
onError: () => {
Expand Down
30 changes: 21 additions & 9 deletions src/lib/db/schema/invitations.query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { count, eq } from "drizzle-orm";
import { nanoid } from "nanoid";
import { getAuth } from "~/lib/auth/utils";
import { db } from "~/lib/db";
import {
invitations,
Expand All @@ -11,14 +12,14 @@ import {

type CreateInvitationParams = Omit<
InvitationInsert,
"id" | "eventUrl" | "createdAt" | "updatedAt"
"id" | "userId" | "eventUrl" | "createdAt" | "updatedAt"
>;

type UpdateInvitationParams = {
id: string;
title?: string;
eventUrl?: string;
customFields?: Record<string, any>;
id: Invitation["id"];
title?: Invitation["title"];
customFields?: Invitation["customFields"];
eventUrl?: Invitation["eventUrl"];
};

export async function getAllInvitations() {
Expand All @@ -41,18 +42,28 @@ export async function getInvitationByEventUrl(eventUrl: string) {
return responses[0];
}

export async function getInvitationsByUserId(
userId: Invitation["userId"],
): Promise<Invitation[]> {
export async function getInvitationsByUserId(): Promise<Invitation[]> {
const auth = await getAuth();

if (!auth.user) {
throw new Error("No Auth");
}

return await db
.select()
.from(invitations)
.where(eq(invitations.userId, userId));
.where(eq(invitations.userId, auth.user.id));
}

export async function createInvitation(
params: CreateInvitationParams,
): Promise<InvitationInsert> {
const auth = await getAuth();

if (!auth.user) {
throw new Error("No Auth");
}

const id = nanoid();
const currentTimestamp = new Date();

Expand All @@ -62,6 +73,7 @@ export async function createInvitation(
.values({
...params,
id,
userId: auth.user.id,
eventUrl: id,
createdAt: currentTimestamp,
updatedAt: currentTimestamp,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/db/schema/invitations.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { json, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import type { EditorData } from "~/components/editor/type";
import { users } from "~/lib/db/schema/users";

export const invitations = pgTable("invitation", {
id: text("id").primaryKey(),
userId: text("user_id")
.references(() => users.id)
.notNull(),
customFields: json("custom_fields").notNull().$type<Record<string, any>>(),
customFields: json("custom_fields").notNull().$type<EditorData>(),
title: text("title").notNull(),
eventUrl: text("event_url").unique().notNull(),
createdAt: timestamp("created_at", {
Expand Down
Loading