Skip to content

Commit

Permalink
Merge pull request #302 from GAMZA-BAT/main
Browse files Browse the repository at this point in the history
[ Deploy ] 0.4.7 1차 QA 최종 반영
  • Loading branch information
j-nary authored Jan 18, 2025
2 parents 3749f98 + 50cc75a commit 9a3ab63
Show file tree
Hide file tree
Showing 29 changed files with 233 additions and 58 deletions.
22 changes: 13 additions & 9 deletions src/app/api/groups/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
MemberRoleRequest,
Role,
} from "@/app/api/groups/type";
import { notFound } from "next/navigation";

export const postCreateGroup = async (formData: FormData) => {
const response = await kyFileInstance
Expand Down Expand Up @@ -100,15 +101,18 @@ export const postJoinGroupByCode = async (code: string) => {
};

export const getRoleByGroupId = async (groupId: number) => {
const response = await kyInstance
.get<Role>(`api/groups/${groupId}/role`, {
next: {
tags: ["role"],
},
})
.text();

return response as Role;
try {
const response = await kyInstance
.get<{ role: Role }>(`api/groups/${groupId}/role`, {
next: {
tags: ["role"],
},
})
.json();
return response.role;
} catch (_error) {
notFound();
}
};

export const deleteGroupMember = async (userId: number, groupId: number) => {
Expand Down
2 changes: 2 additions & 0 deletions src/app/group/[groupId]/problem-list/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const ProblemListPage = ({
/>
<ProblemSection
title="만료된 문제"
isExpired
list={expiredList ?? []}
totalPages={expiredTotalPages}
currentPage={expiredPage}
Expand Down Expand Up @@ -134,6 +135,7 @@ const ProblemListPage = ({
/>
<ProblemSection
title="만료된 문제"
isExpired
list={expiredList ?? []}
totalPages={expiredTotalPages}
currentPage={expiredPage}
Expand Down
31 changes: 27 additions & 4 deletions src/app/group/[groupId]/problem-list/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,49 @@ import {
type problemActionRequest,
} from "@/app/group/[groupId]/problem-list/action";
import { useToast } from "@/common/hook/useToast";
import { HTTP_ERROR_STATUS } from "@/shared/constant/api";
import {
useMutation,
useQueryClient,
useSuspenseQuery,
} from "@tanstack/react-query";
import type { HTTPError } from "ky";

export const usePostProblemMutation = (groupId: number) => {
const queryClient = useQueryClient();
const { showToast } = useToast();
return useMutation({
mutationFn: ({ groupId, link, startDate, endDate }: problemActionRequest) =>
mutationFn: ({
link,
startDate,
endDate,
}: Omit<problemActionRequest, "groupId">) =>
postProblemAction({ groupId, link, startDate, endDate }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["inProgressProblem", "queuedProblem", groupId],
queryKey: ["inProgressProblem", groupId, 0],
});
queryClient.invalidateQueries({
queryKey: ["queuedProblem", groupId, 0],
});
showToast("문제가 정상적으로 등록되었어요.", "success");
},
onError: () => {
showToast("문제가 정상적으로 등록되지 않았어요.", "error");
onError: (error: HTTPError) => {
const { response } = error;

switch (response.status) {
case HTTP_ERROR_STATUS.NOT_FOUND:
showToast("존재하지 않는 그룹입니다.", "error");
break;
case HTTP_ERROR_STATUS.FORBIDDEN:
showToast("문제 생성 권한이 없습니다.", "error");
break;
case HTTP_ERROR_STATUS.BAD_REQUEST:
showToast("링크가 유효하지 않습니다", "error");
break;
default:
showToast("문제가 정상적으로 등록되지 않았어요.", "error");
}
},
});
};
Expand Down
10 changes: 7 additions & 3 deletions src/app/group/[groupId]/withdraw/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

import Modal from "@/common/component/Modal";
import Sidebar from "@/common/component/Sidebar";
import WithdrawDialog from "@/shared/component/WithdrawDialog";
import { sidebarWrapper } from "@/styles/shared.css";
import WithdrawDialog from "@/view/group/index/WithdrawDialog";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";

const WithdrawPage = ({ params }: { params: { groupId: string } }) => {
const router = useRouter();

const userNickname = useSession().data?.user?.nickname;
return (
<main className={sidebarWrapper}>
<Sidebar />
<Modal isOpen={true} onClose={() => router.back()} hasCloseBtn>
<WithdrawDialog groupId={+params.groupId} />
<WithdrawDialog
groupId={+params.groupId}
onSuccess={() => router.push(`/${userNickname}`)}
/>
</Modal>
</main>
);
Expand Down
12 changes: 12 additions & 0 deletions src/asset/svg/icn_solved.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/asset/svg/icn_unsolved.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/asset/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ export { default as IcnSilver2 } from "./icn_silver2.svg";
export { default as IcnSilver3 } from "./icn_silver3.svg";
export { default as IcnSilver4 } from "./icn_silver4.svg";
export { default as IcnSilver5 } from "./icn_silver5.svg";
export { default as IcnSolved } from "./icn_solved.svg";
export { default as IcnSquare } from "./icn_square.svg";
export { default as IcnTrash } from "./icn_trash.svg";
export { default as IcnUser } from "./icn_user.svg";
export { default as IcnUser2 } from "./icn_user2.svg";
export { default as IcnUser3 } from "./icn_user3.svg";
export { default as IcnUnsolved } from "./icn_unsolved.svg";
export { default as IcnUnrank } from "./icn_unrank.svg";
6 changes: 5 additions & 1 deletion src/common/component/SelectBox/index.css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { theme } from "@/styles/themes.css";
import { scrollTheme, theme } from "@/styles/themes.css";
import { style } from "@vanilla-extract/css";
import { recipe } from "@vanilla-extract/recipes";

Expand Down Expand Up @@ -30,6 +30,10 @@ export const optionWrapper = recipe({
flexDirection: "column",
gap: "0.4rem",

maxHeight: "40rem",
overflowY: "scroll",
...scrollTheme.scrollbar,

padding: "1.6rem 1rem",

borderRadius: "8px",
Expand Down
15 changes: 15 additions & 0 deletions src/common/hook/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect, useState } from "react";

export const useDebounce = (value: string, delay: number) => {
const [debounceValue, setDebounceValue] = useState(value);

useEffect(() => {
const timeout = setTimeout(() => {
setDebounceValue(value);
}, delay);

return () => clearTimeout(timeout);
}, [value, delay]);

return debounceValue;
};
15 changes: 11 additions & 4 deletions src/shared/component/Pagination/index.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,30 @@ export const paginationButtonStyle = recipe({
alignItems: "center",
justifyContent: "center",

padding: "0.5rem",
border: "none",
width: "2.2rem",
height: "2.2rem",

border: "none",
borderRadius: "50%",
cursor: "pointer",

...theme.font.Caption3_M_12,
color: theme.color.mg2,
backgroundColor: "transparent",
borderRadius: "0.375rem",

":disabled": {
cursor: "default",
},

":hover": {
backgroundColor: theme.color.mg4,
},
},
variants: {
isActive: {
true: {
backgroundColor: "#f3f4f6",
color: theme.color.white,
backgroundColor: theme.color.mg3,
},
},
},
Expand Down
10 changes: 5 additions & 5 deletions src/shared/component/ProblemList/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import type { ProblemContent } from "@/app/api/problems/type";
import CheckBox from "@/common/component/CheckBox";
import { IcnSolved, IcnUnsolved } from "@/asset/svg";
import ProblemEdit from "@/shared/component/ProblemList/ProblemEdit";
import {
checkboxStyle,
Expand All @@ -22,6 +22,7 @@ import Link from "next/link";
type ProblemListItemProps = Omit<ProblemContent, "startDate"> & {
isOwner?: boolean;
className?: string;
isExpired?: boolean;
};

const JSX_BY_STATUS = {
Expand All @@ -32,8 +33,8 @@ const JSX_BY_STATUS = {
className={clsx(checkboxStyle, wrongCheckBoxStyle)}
/>
),
unsolved: <CheckBox checked={false} className={checkboxStyle} />,
solved: <CheckBox checked={true} className={checkboxStyle} />,
unsolved: <IcnUnsolved className={checkboxStyle} />,
solved: <IcnSolved className={checkboxStyle} />,
};

const ProblemListItem = ({
Expand All @@ -47,12 +48,11 @@ const ProblemListItem = ({
memberCount,
submitMemberCount,
isOwner = false,
isExpired = false,
}: ProblemListItemProps) => {
const groupId = useGetGroupId();
const Icon = getTierImage(level);

const isExpired = new Date(endDate).getTime() - new Date().getTime() <= 0;

const status = solved ? "solved" : isExpired ? "wrong" : "unsolved";

const { isActive, handleBlur, handleFocus, handleMouseOut, handleMouseOver } =
Expand Down
1 change: 0 additions & 1 deletion src/shared/component/PromptModal/index.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export const promptModalWrapper = style({
background: theme.color.mg6,

borderRadius: "16px",
opacity: "0.9",
});

export const metaTextStyle = style({
Expand Down
23 changes: 16 additions & 7 deletions src/shared/component/SolvedFilterBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,28 @@ import type { SolvedFilterType } from "@/shared/type/solvedFilter";

type SolvedFilterBarProps = {
option: SolvedFilterType;
onChange: (option: SolvedFilterType) => void;
onChangeOption: (option: SolvedFilterType) => void;
idFilterValue: string;
onChangeIdFilter: (value: string) => void;
defaultValue: SolvedFilterType;
};

const SolvedFilterBar = ({
option,
onChange,
onChangeOption,
idFilterValue,
onChangeIdFilter,
defaultValue,
}: SolvedFilterBarProps) => {
const handleLanguageChange = (newLanguage: string) => {
onChange({
onChangeOption({
...option,
language: newLanguage as SolvedFilterType["language"],
});
};

const handleResultChange = (newResult: string) => {
onChange({
onChangeOption({
...option,
result: newResult as SolvedFilterType["result"],
});
Expand All @@ -44,7 +48,12 @@ const SolvedFilterBar = ({
return (
<div className={solvedFilterWrapper}>
<Input className={inputStyle} placeholder="문제 번호" />
<Input className={inputStyle} placeholder="아이디" />
<Input
className={inputStyle}
value={idFilterValue}
onChange={(e) => onChangeIdFilter(e.target.value)}
placeholder="아이디"
/>
<SelectBox
label="모든 언어"
options={SOLVED_LANGUAGE}
Expand All @@ -68,8 +77,8 @@ const SolvedFilterBar = ({
width={44}
height={44}
aria-label="풀이 리스트 필터링 초기화"
onClick={() => onChange(defaultValue)}
onKeyDown={handleA11yClick(() => onChange(defaultValue))}
onClick={() => onChangeOption(defaultValue)}
onKeyDown={handleA11yClick(() => onChangeOption(defaultValue))}
tabIndex={0}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
descTextStyle,
descWrapper,
metaTextStyle,
} from "@/view/group/index/WithdrawDialog/index.css";
} from "@/shared/component/WithdrawDialog/index.css";

const PromptWithdraw = () => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Animation from "@/common/component/Animation";
import {
metaTextStyle,
successStyle,
} from "@/view/group/index/WithdrawDialog/index.css";
} from "@/shared/component/WithdrawDialog/index.css";

const SuccessWithdraw = () => {
return (
Expand Down
Loading

0 comments on commit 9a3ab63

Please sign in to comment.