Skip to content

Commit

Permalink
Merge pull request #62 from DDD-Community/feat/#46
Browse files Browse the repository at this point in the history
[feat/#46] 크루 상세보기, 크루 만들기 기능 추가중
  • Loading branch information
lkhoony authored Sep 14, 2024
2 parents 2d57767 + cdaf647 commit 3427853
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 73 deletions.
20 changes: 20 additions & 0 deletions src/api/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ export const getGroups = async (groupsReq: groupsReq): Promise<groupsRes> => {
}
}

export const getGroup = async (id: number): Promise<group> => {
try {
const res = await axiosInstance.get(`/groups/${id}`)
return res.data.data
} catch (e) {
throw e
}
}

export const joinGroup = async (groupJoinReq: groupJoinReq): Promise<groupJoinRes> => {
try {
// eslint-disable-next-line max-len
Expand All @@ -72,3 +81,14 @@ export const joinGroup = async (groupJoinReq: groupJoinReq): Promise<groupJoinRe
throw e
}
}

export const checkGroupName = async (name: string): Promise<boolean> => {
try {
// eslint-disable-next-line max-len
const res = await axiosInstance.post(`groups/check`, { name })
const errorMessage = res.data?.errorMessage
return errorMessage ? false : true
} catch (e) {
throw e
}
}
21 changes: 12 additions & 9 deletions src/components/Crew/CrewList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { group, groupsReq } from "@/api"
import { group, groupsReq, sort } from "@/api"
import EmptyCrewImage from "@/assets/images/crew-empty.png"
import CrewItem from "@/components/Crew/CrewItem"
import { useGetGroups } from "@/hooks/useGroupMutation"
Expand All @@ -15,13 +15,12 @@ const SORT_LIST = [
]

const CrewList = (): ReactElement => {
const [sort, setSort] = useState<number>(0)
const [mode] = useState<"my" | "list">("my")
const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false)

const [params] = useState<groupsReq>({
const [params, setParams] = useState<groupsReq>({
page: 0,
size: 10,
size: 10000,
sort: "userCount,desc",
})

Expand All @@ -37,8 +36,9 @@ const CrewList = (): ReactElement => {
})
}

const openJoinCrewModal = (): void => {
const openJoinCrewModal = (id: number): void => {
openModal(modals.joinCrewModal, {
id,
onSubmit: () => {
console.log("open")
},
Expand Down Expand Up @@ -66,7 +66,7 @@ const CrewList = (): ReactElement => {
key={`sort-list-${s.sort}`}
className="cursor-pointer text-[13px] font-medium leading-[24px] text-zinc-400"
onClick={() => {
setSort(i)
setParams({ ...params, sort: s.sort as sort })
setIsDropdownOpen(false)
}}
>
Expand All @@ -89,7 +89,7 @@ const CrewList = (): ReactElement => {
return (
<div className="flex flex-grow flex-col gap-[8px]">
{_groups.map((g) => (
<CrewItem key={`crew-item-${g.id}`} group={g} onClickDetail={openJoinCrewModal} />
<CrewItem key={`crew-item-${g.id}`} group={g} onClickDetail={() => openJoinCrewModal(g.id)} />
))}
</div>
)
Expand All @@ -113,7 +113,10 @@ const CrewList = (): ReactElement => {
{mode === "my" && <MyCrewRankingContainer openCreateModal={openCreateModal} openInviteModal={openInviteModal} />}
{/* header */}
<div className="mb-[24px] flex w-full items-center">
<div className="flex-grow text-[22px] font-bold text-zinc-900">전체크루(0)</div>
<div className="flex-grow text-[22px] font-bold text-zinc-900">
<span>전체크루</span>
<span>{isLoading ? "" : `(${data?.totalCount})`}</span>
</div>
{mode === "list" && (
<div
className="flex w-[138px] cursor-pointer items-center justify-center gap-[10px] rounded-[33px] bg-zinc-800 p-[10px] text-sm font-semibold text-white"
Expand All @@ -129,7 +132,7 @@ const CrewList = (): ReactElement => {
<div className="relative mb-[12px] text-sm font-medium text-zinc-500" ref={dropdownRef}>
<div className="flex cursor-pointer items-center" onClick={toggleDropdown}>
<SortCrewIcon />
<div>{SORT_LIST[sort].label}</div>
<div>{SORT_LIST.find((s) => s.sort === params.sort)?.label}</div>
</div>

{/* dropdown */}
Expand Down
145 changes: 82 additions & 63 deletions src/components/Modal/JoinCrewModal.tsx
Original file line number Diff line number Diff line change
@@ -1,93 +1,112 @@
import ModalContainer from "@components/ModalContainer"
import CrewJoinUserIcon from "@assets/icons/crew-join-user-icon.svg?react"
import PrivateCrewIcon from "@assets/icons/crew-private-icon.svg?react"
import { useState } from "react"
import { ReactNode, useState } from "react"
import { ModalProps } from "@/contexts/ModalsContext"
import { useGetGroup } from "@/hooks/useGroupMutation"

const JoinCrewModal = (props: ModalProps): React.ReactElement => {
const { onClose, onSubmit } = props
const { onClose, onSubmit, id } = props

const [joinCode, setJoinCode] = useState<string>("")
const [isCodeError, setIsCodeError] = useState<boolean>(false)

const { data, isLoading, isError } = useGetGroup(id)

const onChangeJoinCode = (e: React.ChangeEvent<HTMLInputElement>): void => {
if (isCodeError) setIsCodeError(false)
if (e.target.value.length <= 4) setJoinCode(e.target.value)
}

return (
<ModalContainer onClose={onClose}>
<div className="flex w-full flex-col items-center">
{/* header */}
<div className="mb-[40px] flex w-full items-center gap-[16px]">
<div className="flex items-center gap-1.5">
<PrivateCrewIcon />
<div className="text-xl font-bold text-zinc-900">{"주인공 다 모여랏"}</div>
</div>

<div className="flex items-center gap-1">
<CrewJoinUserIcon />
<div className="text-sm font-medium">7/30명</div>
const createRank = (): ReactNode => {
return (
<div className="flex gap-[7px]">
{data?.ranks.map((r) => (
<div className="flex h-[108px] w-[106px] flex-col items-center justify-center rounded-xl border border-gray-200 p-3">
<div className="mb-2 text-sm font-semibold text-zinc-700">{`${r.rank}등`}</div>
<div className="mb-1 max-w-full overflow-hidden text-ellipsis whitespace-nowrap text-lg font-semibold text-zinc-700">{`${r.name}`}</div>
</div>
</div>
))}
</div>
)
}

<div className="flex w-full flex-col gap-[20px]">
{/* crew owner */}
<div className="flex flex-col gap-1">
<div className="text-[15px] font-semibold">크루장</div>
<div className="rounded-xl border border-gray-200 bg-zinc-100 p-[12px] text-[15px] font-normal text-zinc-900">
주인공
return (
<ModalContainer onClose={onClose}>
{isLoading ? (
"로딩 중입니다."
) : isError ? (
"데이터를 불러오지 못했습니다."
) : (
<div className="flex w-full flex-col items-center">
{/* header */}
<div className="mb-[40px] flex w-full items-center gap-[16px]">
<div className="flex items-center gap-1.5">
{data?.isHidden && <PrivateCrewIcon />}
<div className="text-xl font-bold text-zinc-900">{data?.name}</div>
</div>
</div>

{/* crew description */}
<div className="flex flex-col gap-1">
<div className="text-[15px] font-semibold">크루소개</div>
<div className="h-[80px] overflow-scroll rounded-xl border border-gray-200 bg-zinc-100 p-[12px] text-[15px] font-normal text-zinc-900">
주인공
<div className="flex items-center gap-1">
<CrewJoinUserIcon />
<div className="text-sm font-medium">{`${data?.userCount}/${data?.userCapacity}명`}</div>
</div>
</div>
{!data?.isHidden ? (
<div className="mb-6 flex w-full flex-col gap-[20px]">
{/* crew owner */}
<div className="flex flex-col gap-1">
<div className="text-[15px] font-semibold">크루장</div>
<div className="rounded-xl border border-gray-200 bg-zinc-100 p-[12px] text-[15px] font-normal text-zinc-900">
{data?.ownerUid}
</div>
</div>

{/* crew rank */}
<div className="mb-6 flex flex-col gap-1">
<div className="flex items-center gap-2">
<div className="text-[15px] font-semibold">오늘 바른자세 랭킹</div>
<div className="text-[14px] font-medium text-[#1A75FF]">크루에 가입하면 볼 수 있어요</div>
{/* crew description */}
<div className="flex flex-col gap-1">
<div className="text-[15px] font-semibold">크루소개</div>
<div className="h-[80px] overflow-scroll rounded-xl border border-gray-200 bg-zinc-100 p-[12px] text-[15px] font-normal text-zinc-900">
{data?.description}
</div>
</div>

{/* crew rank */}
{data?.ranks && (
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<div className="text-[15px] font-semibold">오늘 바른자세 랭킹</div>
<div className="text-[14px] font-medium text-[#1A75FF]">크루에 가입하면 볼 수 있어요</div>
</div>
<div className="flex gap-[7px]">{createRank()}</div>
</div>
)}
</div>
<div className="flex gap-[7px]">
<div className="flex h-[108px] w-[106px] flex-col items-center justify-center rounded-xl border border-gray-200 p-3">
<div className="mb-2 text-sm font-semibold text-zinc-700">1등</div>
<div className="mb-1 text-lg font-semibold text-zinc-700">?</div>
<div className="text-base text-zinc-500">29일</div>
) : (
// private crew
<div className="mb-6 flex w-full flex-col gap-1">
<div className="text-[15px] font-semibold">비공개 크루입니다. 비밀번호를 입력해주세요. (숫자 4자리)</div>
<input
type="password"
className={`w-full rounded-xl border border-gray-200 p-3 text-[15px] outline-none ${
isCodeError ? "border-red-500" : "border-gray-200"
}`}
value={joinCode}
onChange={onChangeJoinCode}
/>
<div className={`text-sm font-semibold text-red-500 ${isCodeError ? "opacity-100" : "opacity-0"}`}>
비밀번호가 틀렸습니다.
</div>
</div>
</div>
</div>
)}

{/* private crew */}
<div className="mb-6 flex w-full flex-col gap-1">
<div className="text-[15px] font-semibold">비공개 크루입니다. 비밀번호를 입력해주세요. (숫자 4자리)</div>
<input
type="password"
className={`w-full rounded-xl border border-gray-200 p-3 text-[15px] outline-none ${
isCodeError ? "border-red-500" : "border-gray-200"
}`}
value={joinCode}
onChange={onChangeJoinCode}
/>
<div className={`text-sm font-semibold text-red-500 ${isCodeError ? "opacity-100" : "opacity-0"}`}>
비밀번호가 틀렸습니다.
</div>
{/* button */}
<button
className="w-[256px] rounded-[40px] bg-[#1A75FF] px-10 py-3 text-base font-semibold text-white"
onClick={onSubmit}
>
크루 가입하기
</button>
</div>

{/* button */}
<button
className="w-[256px] rounded-[40px] bg-[#1A75FF] px-10 py-3 text-base font-semibold text-white"
onClick={onSubmit}
>
크루 가입하기
</button>
</div>
)}
</ModalContainer>
)
}
Expand Down
28 changes: 27 additions & 1 deletion src/hooks/useGroupMutation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { useMutation, UseMutationResult, useQuery, UseQueryResult } from "@tanstack/react-query"
import { getGroups, groupJoinReq, groupJoinRes, groupsReq, groupsRes, joinGroup } from "@/api"
import {
checkGroupName,
getGroup,
getGroups,
group,
groupJoinReq,
groupJoinRes,
groupsReq,
groupsRes,
joinGroup,
} from "@/api"

export const useGetGroups = (params: groupsReq): UseQueryResult<groupsRes, Error> => {
// eslint-disable-next-line max-len
return useQuery<groupsRes, Error>({ queryKey: ["groups", params], queryFn: () => getGroups(params) })
}

export const useGetGroup = (id: number): UseQueryResult<group, Error> => {
// eslint-disable-next-line max-len
return useQuery<group, Error>({ queryKey: ["group", id], queryFn: () => getGroup(id) })
}

export const useJoinGroup = (): UseMutationResult<groupJoinRes, unknown, groupJoinReq, unknown> => {
return useMutation({
mutationFn: (groupJoinReq: groupJoinReq) => {
Expand All @@ -16,3 +31,14 @@ export const useJoinGroup = (): UseMutationResult<groupJoinRes, unknown, groupJo
},
})
}

export const useCheckGroupName = (): UseMutationResult<boolean, unknown, string, unknown> => {
return useMutation({
mutationFn: (name: string) => {
return checkGroupName(name)
},
onSuccess: (data) => {
console.log(data)
},
})
}

0 comments on commit 3427853

Please sign in to comment.