Skip to content

Commit

Permalink
Merge pull request #98 from iOdiO89/97-직원초대링크-생성과-가입-플로우를-안정화한다
Browse files Browse the repository at this point in the history
 fix: 초대링크를 통한 가입시 storeId 받아올 수 있게 로직 변경
  • Loading branch information
DeveloperRyou authored Jul 13, 2024
2 parents a52de81 + f46ed42 commit 7507fcb
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 104 deletions.
27 changes: 27 additions & 0 deletions src/apis/dynamodb.ts
Original file line number Diff line number Diff line change
@@ -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<InviteResponse>(
`/api/dynamoDB?id=${inviteDataId}`,
);
return data;
}

async function postInviteData(body: InviteResponse) {
const { data } = await axios.post("/api/dynamoDB", body);
return data;
}

export { getInviteData, postInviteData };
29 changes: 29 additions & 0 deletions src/hooks/query/dynamodb.ts
Original file line number Diff line number Diff line change
@@ -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 };
37 changes: 34 additions & 3 deletions src/hooks/query/relation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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,
};
20 changes: 12 additions & 8 deletions src/libs/copy.ts
Original file line number Diff line number Diff line change
@@ -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");
Expand All @@ -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);
};
74 changes: 28 additions & 46 deletions src/pages/oauth/redirect.tsx
Original file line number Diff line number Diff line change
@@ -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<InviteResponse>(
`/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]);
}
79 changes: 32 additions & 47 deletions src/screen/manage/ShareLink.tsx
Original file line number Diff line number Diff line change
@@ -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<string>("");
const [linkCopied, setLinkCopied] = useState(false);
const [showToastMsg, setShowToastMsg] = useState<boolean>(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 (
<>
Expand All @@ -91,15 +77,15 @@ function ShareLink() {
<div className="B1-medium text-Gray5 mt-4">
링크복사가 안되었나요?
</div>
<button onClick={() => handleCopyLink()} type="button">
<button onClick={handleCopyLink} type="button">
<FlexBox direction="row">
<div className="B4-regular text-Gray4 underline">링크 복사</div>
<div className="B4-regular text-Gray4">하기</div>
</FlexBox>
</button>
</FlexBox>
</FlexBox>
{linkCopied && (
{showToastMsg && (
<div className="w-full B5-regular px-4 py-4 mb-4 bg-[#2D2D2D] text-white">
<p className="mb-4">링크가 자동으로 복사되었습니다.</p>
</div>
Expand All @@ -109,4 +95,3 @@ function ShareLink() {
}

export default ShareLink;
export type { InviteDataType };

0 comments on commit 7507fcb

Please sign in to comment.