diff --git a/src/apis/dynamodb.ts b/src/apis/dynamodb.ts new file mode 100644 index 0000000..bafd7d3 --- /dev/null +++ b/src/apis/dynamodb.ts @@ -0,0 +1,27 @@ +import { InviteSchedule } from "@/data/inviteSchedule"; +import axios from "axios"; + +export interface InviteResponse { + id: string; + inviteData: InviteDataType; +} +interface InviteDataType { + storeId: string; + position: string; + schedule: InviteSchedule; + createdAt: string; +} + +async function getInviteData(inviteDataId: string) { + const { data } = await axios.get( + `/api/dynamoDB?id=${inviteDataId}`, + ); + return data; +} + +async function postInviteData(body: InviteResponse) { + const { data } = await axios.post("/api/dynamoDB", body); + return data; +} + +export { getInviteData, postInviteData }; diff --git a/src/hooks/query/dynamodb.ts b/src/hooks/query/dynamodb.ts new file mode 100644 index 0000000..9b1806e --- /dev/null +++ b/src/hooks/query/dynamodb.ts @@ -0,0 +1,29 @@ +import { InviteResponse, getInviteData, postInviteData } from "@/apis/dynamodb"; +import { myAtom } from "@/data/global"; +import { copyLink } from "@/libs/copy"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useAtom } from "jotai"; + +function useGetInviteData() { + const [my] = useAtom(myAtom); + const inviteId = localStorage.getItem("inviteDataId"); + const { data, isSuccess } = useQuery({ + queryKey: ["getInviteData"], + queryFn: () => getInviteData(inviteId as string), + enabled: !(my?.id === undefined || my?.id === null || inviteId === null), + }); + + return { data, isSuccess }; +} + +function usePostInviteData(inviteId: string) { + const { mutate, isSuccess } = useMutation({ + mutationKey: ["getInviteData"], + mutationFn: (body: InviteResponse) => postInviteData(body), + onSuccess: () => copyLink(inviteId), + }); + + return { mutate, isSuccess }; +} + +export { useGetInviteData, usePostInviteData }; diff --git a/src/hooks/query/relation.ts b/src/hooks/query/relation.ts index d51bc39..9bed1b2 100644 --- a/src/hooks/query/relation.ts +++ b/src/hooks/query/relation.ts @@ -9,6 +9,10 @@ import { import { storeIdAtom } from "@/data/global"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useAtom } from "jotai"; +import { useRouter } from "next/router"; +import { InviteSchedule } from "@/data/inviteSchedule"; +import { usePostPlanList } from "./plan"; +import { useGetMyQueryKey } from "./my"; interface UsePostRelationProps { storeId: string; @@ -35,12 +39,12 @@ function useGetRelationList() { } function usePostRelation() { - const { mutate, isSuccess } = useMutation({ + const { mutateAsync } = useMutation({ mutationKey: ["postRelationMutate"], - mutationFn: ({ storeId, memberId, body }: UsePostRelationProps) => + mutationFn: async ({ storeId, memberId, body }: UsePostRelationProps) => postRelation(storeId, memberId, body), }); - return { mutate, isSuccess }; + return { mutateAsync }; } function usePostRelationAdmin() { @@ -64,9 +68,36 @@ function usePostRelationAdmin() { return { mutate }; } +function useStaffJoin() { + const { mutateAsync: postRelationMutate } = usePostRelation(); + const { mutate: postPlanListMutate } = usePostPlanList(); + const queryClient = useQueryClient(); + const router = useRouter(); + + const { mutate } = useMutation({ + mutationKey: ["StaffJoin"], + mutationFn: async ({ + storeId, + memberId, + body, + inviteSchedule, + }: UsePostRelationProps & { inviteSchedule: InviteSchedule }) => { + await postRelationMutate({ storeId, memberId, body }); + postPlanListMutate({ storeId, memberId, inviteSchedule }); + }, + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: [useGetMyQueryKey] }); + localStorage.removeItem("inviteDataId"); + router.push("/main"); + }, + }); + return { mutate }; +} + export { useGetRelation, useGetRelationList, usePostRelation, usePostRelationAdmin, + useStaffJoin, }; diff --git a/src/libs/copy.ts b/src/libs/copy.ts index e32c717..dc9bf76 100644 --- a/src/libs/copy.ts +++ b/src/libs/copy.ts @@ -1,14 +1,13 @@ -export default function copy( - text: string, - onSuccess?: () => void, - onError?: (err: Error) => void, -) { +const copy = (text: string, onSuccess?: () => void) => { if (navigator.clipboard) { // (크롬 66버전 이상일때만 사용 가능) - navigator.clipboard.writeText(text).then(onSuccess).catch(onError); + navigator.clipboard + .writeText(text) + .then(onSuccess) + .catch(error => console.log("링크를 복사하는데 실패했습니다: ", error)); } else { if (!document.queryCommandSupported("copy")) { - onError && onError(new Error("복사하기가 지원되지 않는 브라우저입니다.")); + console.log("복사하기가 지원되지 않는 브라우저입니다."); return; } const textarea = document.createElement("textarea"); @@ -26,4 +25,9 @@ export default function copy( document.body.removeChild(textarea); onSuccess && onSuccess(); } -} +}; + +export const copyLink = (inviteId: string, onSuccess?: () => void) => { + const link = `${window.location.origin}/?id=${inviteId}`; + copy(link, onSuccess); +}; diff --git a/src/pages/oauth/redirect.tsx b/src/pages/oauth/redirect.tsx index 3694bf3..5a41f73 100644 --- a/src/pages/oauth/redirect.tsx +++ b/src/pages/oauth/redirect.tsx @@ -1,60 +1,42 @@ import { PostRelationBody } from "@/apis/relation"; import { myAtom } from "@/data/global"; -import { usePostPlanList } from "@/hooks/query/plan"; -import { usePostRelation } from "@/hooks/query/relation"; -import { InviteResponse, InviteDataType } from "@/screen/manage/ShareLink"; -import axios from "axios"; +import { useGetInviteData } from "@/hooks/query/dynamodb"; +import { useStaffJoin } from "@/hooks/query/relation"; import { useAtom } from "jotai"; import { useRouter } from "next/router"; import { useEffect } from "react"; export default function Redirect() { - const { push } = useRouter(); + const router = useRouter(); + const [my] = useAtom(myAtom); - const { mutate: postRelationMutate } = usePostRelation(); - const { mutate: postPlanListMutate } = usePostPlanList(); - async function getInviteData(inviteDataId: string) { - const response = await axios.get( - `/api/dynamoDB?id=${inviteDataId}`, - ); - return response.data; - } - const createNewEmployee = (inviteData: InviteDataType, memberId: string) => { - const body: PostRelationBody = { - role: "STAFF", - position: inviteData.position, - }; - postRelationMutate( - { storeId: inviteData.storeId, memberId: my?.id as string, body }, - { - onSuccess: () => - postPlanListMutate({ - storeId: inviteData.storeId, - memberId, - inviteSchedule: inviteData.schedule, - }), - onError: () => console.log("fail"), - }, - ); - }; + const { data: inviteResponse, isSuccess } = useGetInviteData(); + const { mutate: staffJoinMutate } = useStaffJoin(); + useEffect(() => { - if (my?.id === undefined || my?.id === null) return; - if (localStorage.getItem("inviteDataId") !== null) { - const inviteDataId = String(localStorage.getItem("inviteDataId")); - getInviteData(inviteDataId) - .then(data => { - createNewEmployee(data.inviteData, my?.id); - localStorage.removeItem("inviteDataId"); - push("/main"); - }) - .catch(() => { - push("/main"); - }); + const inviteId = localStorage.getItem("inviteDataId"); + if (inviteId !== null) { + // 1. 직원초대링크를 통해 들어온 새 직원 + if (isSuccess && inviteResponse) { + const body: PostRelationBody = { + role: "STAFF", + position: inviteResponse.inviteData.position, + }; + const inviteRequestBody = { + storeId: inviteResponse.inviteData.storeId, + memberId: my?.id as string, + body, + inviteSchedule: inviteResponse.inviteData.schedule, + }; + staffJoinMutate(inviteRequestBody); + } } else if (my?.relationList.length === 0) { - push("/signup"); + // 2. 회원가입 + router.push("/signup"); } else { - push("/main"); + // 3. 기존회원 로그인 + router.push("/main"); } - }, [my]); + }, [isSuccess]); } diff --git a/src/screen/manage/ShareLink.tsx b/src/screen/manage/ShareLink.tsx index 22baf18..8aac760 100644 --- a/src/screen/manage/ShareLink.tsx +++ b/src/screen/manage/ShareLink.tsx @@ -1,74 +1,60 @@ import { storeIdAtom } from "@/data/global"; import { - InviteSchedule, inviteScheduleAtom, selectedPositionAtom, } from "@/data/inviteSchedule"; -import copy from "@/libs/copy"; +import { usePostInviteData } from "@/hooks/query/dynamodb"; +import { copyLink } from "@/libs/copy"; import { createRandomString } from "@/libs/createRandomId"; import FlexBox from "@modules/layout/FlexBox"; -import axios from "axios"; import dayjs from "dayjs"; import { useAtom } from "jotai"; import Image from "next/image"; import { useEffect, useState } from "react"; -export interface InviteResponse { - id: string; - inviteData: InviteDataType; -} - -interface InviteDataType { - storeId: string; - position: string; - schedule: InviteSchedule; - createdAt: string; -} - function ShareLink() { const [inviteId, setInviteId] = useState(""); const [linkCopied, setLinkCopied] = useState(false); + const [showToastMsg, setShowToastMsg] = useState(false); const [inviteSchedule] = useAtom(inviteScheduleAtom); const [selectedPosition] = useAtom(selectedPositionAtom); const [storeId] = useAtom(storeIdAtom); + const { mutate, isSuccess } = usePostInviteData(inviteId); + if (!inviteId) setInviteId(createRandomString(8)); const handleCopyLink = () => { - const link = `${window.location.origin}/?id=${inviteId}`; - copy( - link, - () => { - setLinkCopied(true); - }, - err => { - console.log("링크를 복사하는데 실패했습니다: ", err); - }, - ); + copyLink(inviteId, () => setLinkCopied(true)); }; - const sendInviteToDB = async () => { - const inviteData: InviteDataType = { - storeId, - position: selectedPosition, - schedule: inviteSchedule, - createdAt: dayjs().format("YYYY-MM-DD HH:mm:ss"), - }; - const data = { - id: inviteId, - inviteData, - }; - try { - await axios.post("/api/dynamoDB", data); - handleCopyLink(); - } catch (error) { - alert("초대링크 생성에 실패했습니다."); + useEffect(() => { + let timer: NodeJS.Timeout | undefined; + if (isSuccess || linkCopied) { + setShowToastMsg(true); + timer = setTimeout(() => { + setShowToastMsg(false); + }, 2000); } - }; + return () => { + if (timer) clearTimeout(timer); + }; + }, [isSuccess, linkCopied]); useEffect(() => { - sendInviteToDB(); - }, []); + if (inviteId.length > 0) { + const inviteData = { + id: inviteId, + inviteData: { + storeId, + position: selectedPosition, + schedule: inviteSchedule, + createdAt: dayjs().format("YYYY-MM-DD HH:mm:ss"), + }, + }; + mutate(inviteData); + } + }, [inviteId]); return ( <> @@ -91,7 +77,7 @@ function ShareLink() {
링크복사가 안되었나요?
- - {linkCopied && ( + {showToastMsg && (

링크가 자동으로 복사되었습니다.

@@ -109,4 +95,3 @@ function ShareLink() { } export default ShareLink; -export type { InviteDataType };