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

챌린지 인증/기록 페이지 #148 #179

Merged
merged 40 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2fb5f5e
refactor(verification): 기록 페이지의 인증하기 탭
joojjang Sep 28, 2024
6451ef7
refactor(textarea): 컴포넌트에 최소 글자수 텍스트 추가
joojjang Sep 28, 2024
431463b
remove(verification): 안 쓰는 코드 삭제
joojjang Sep 28, 2024
ce3fffc
feat(verification): 사진 삭제 버튼 추가
joojjang Sep 29, 2024
3645bf2
fix(verification): 이미지 업로드 요소 이름 변경, 포인터 추가, 디자인 수정
joojjang Sep 29, 2024
3748755
feat(verification): 업로드된 이미지 border 추가, 삭제 버튼 색상 변경
joojjang Sep 29, 2024
3d098ac
refactor(cta): 높이를 상수로 정의, z-index 설정하여 항상 보이게
joojjang Sep 30, 2024
28d0446
fix(postVerification): 요청 경로 수정, 반환 값 수정 (반환 값 없음)
joojjang Sep 30, 2024
2e92fd8
remove(postVerification): 주석 삭제
joojjang Sep 30, 2024
7ded329
fix(challenge-record): 페이지 경로에 id 추가, id 추출하여 challengeId로 할당
joojjang Sep 30, 2024
c88332d
refactor(caution): 유의사항 컴포넌트 모듈화
joojjang Sep 30, 2024
a66da6c
design(verification): padding 제거하고 자식요소에 각각 여백 추가
joojjang Sep 30, 2024
8b67445
fix(review-write): 여백을 각각의 요소에 넣는 걸로 수정
joojjang Sep 30, 2024
733edaa
refactor(challenge-title): 챌린지 제목 컴포넌트 모듈화
joojjang Sep 30, 2024
f92269a
fix(verification): 이미지 좌우 여백 조정
joojjang Sep 30, 2024
d8fa574
fix(verification): 상하 여백 조정
joojjang Sep 30, 2024
fa80c37
refactor(records): 컴포넌트명 및 파일명 변경 ( StampBoard -> Records)
joojjang Sep 30, 2024
b45683c
refactor(challenge-record): 탭 패널에 해당하는 컴포넌트들 파일 경로 변경
joojjang Sep 30, 2024
2b90206
refactor(records): StampBoard 리팩토링 중
joojjang Sep 30, 2024
99c1923
fix(verification): caution import 경로 수정, 필요 없는 css 속성 삭제
joojjang Sep 30, 2024
88ba239
fix(StampBoard): css 수정
joojjang Sep 30, 2024
35e3a1d
fix(records): api 함수 getChallengeRecord 수정
joojjang Sep 30, 2024
01b00aa
fix(records): getChallengeRecord 부분 수정
joojjang Sep 30, 2024
8202127
feat(records): 스탬프보드 안에 InfoGrid 구현
joojjang Sep 30, 2024
0b5708d
design(records, verification): 상하 여백 조정
joojjang Sep 30, 2024
b31a43f
fix(tab-panel): 높이가 부모 요소를 채우도록 수정
joojjang Sep 30, 2024
6b3543d
chore(stamp): 스탬프 이미지 파일 변경
joojjang Sep 30, 2024
594b880
fix(records): 높이가 부모를 꽉 채우도록 수정
joojjang Sep 30, 2024
a7c0f19
refactor(records): 스탬프 레이아웃 그리드로 변경
joojjang Sep 30, 2024
50b3181
refactor(stamp): 요소 간소화, 커서 포인터가 active일 때만 동작하도록
joojjang Sep 30, 2024
3a852d2
refactor(records): recordIds 세팅하는 부분 변수, 함수명 변경
joojjang Sep 30, 2024
59d8e71
refactor(record-item): 기능에 맞게 이름 변경 (bottom sheet -> record item)
joojjang Sep 30, 2024
0ab8169
refactor(records): api 함수 (getChallengeRecordDetail)와 함수 호출하는 부분 리팩토링
joojjang Sep 30, 2024
2e764fe
docs(records): 함수에 설명 주석 추가
joojjang Sep 30, 2024
b51c6f6
refactor(record-item): css 고치고 리팩토링
joojjang Sep 30, 2024
451b5af
fix(record-item): 바텀에서 띄워진 위치 수정, top-bar z-index 수정
joojjang Sep 30, 2024
aaa376f
fix(record, record-item): 바텀시트 열렸을 때 overflowY 없게, framer 모션 수정
joojjang Sep 30, 2024
3e1a57b
fix(record-item): css 수정
joojjang Sep 30, 2024
35589b9
fix(record-item): 포지션 수정
joojjang Sep 30, 2024
679ec2e
Merge branch 'develop' into Feat/record-page-#148
joojjang Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 42 additions & 22 deletions src/apis/challenge-record/challenge.record.api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AxiosError } from 'axios';

import { multiPartClient, axiosClient } from '../AxiosClient';
import {
ApiResponse,
Expand All @@ -9,35 +11,42 @@ import {

// POST: /api/challenges/{challengeId}/verification
export async function postVerification(
id: number,
image: File,
content: string
): Promise<{ data: ChallengeVerificationData; status: number }> {
const formData = new FormData();
formData.append(
challengeId: number,
content: string,
image: File
): Promise<void> {
const requestBody = new FormData();
requestBody.append(
'body',
new Blob([JSON.stringify({ content })], { type: 'application/json' })
);
formData.append('image', image);
requestBody.append('image', image);

const response = await multiPartClient.post<ChallengeVerificationData>(
`api/challenges/${id}/verifications`,
formData
`api/challenges/${challengeId}/verification`,
requestBody
);
console.log('postVerification response: ', response.data);
// return response.data;
return { data: response.data, status: response.status };
console.log('postVerification response: ', response.data); // test
}

// GET: /api/challenges/{challengeId}/record
export async function getChallengeRecord(
id: number
challengeId: number
): Promise<ChallengeRecordData> {
const response = await axiosClient.get<ApiResponse<ChallengeRecordData>>(
`api/challenges/${id}/record`
);
console.log('getChallengeRecord response: ', response.data);
return response.data.data;
try {
const response = await axiosClient.get(
`api/challenges/${challengeId}/record`
);
// console.log('getChallengeRecord response: ', response.data); // test
return response.data.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new Error(
`getChallengeRecord error: ${error.response?.data.message || error.message}`
);
} else {
throw new Error('getChallengeRecord error: unexpected');
}
}
}

// GET: /api/challenges/record/{recordId}
Expand All @@ -51,11 +60,22 @@ export async function getChallengeRecordDetailorigin(
return response.data.data;
}

export async function getChallengeRecordDetail(
export async function getChallengeRecordDetails(
recordId: number
): Promise<ChallengeRecordDetailData> {
const response = await axiosClient.get(`api/challenges/record/${recordId}`);
return response.data;
try {
const response = await axiosClient.get(`api/challenges/record/${recordId}`);
// console.log('getChallengeRecordDetails response: ', response.data); // test
return response.data.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new Error(
`getChallengeRecord error: ${error.response?.data.message || error.message}`
);
} else {
throw new Error('getChallengeRecord error: unexpected');
}
}
}

// GET: /api/user/challenges/completes
Expand Down
30 changes: 10 additions & 20 deletions src/apis/challenge-record/challenge.record.response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,19 @@ export type ApiResponse<T> = {
};

export type ChallengeRecordData = {
result: string;
data: {
title: string;
totalCount: number;
successCount: number;
startDate: string;
endDate: string;
recordIds: number[];
};
message: string;
errorCode: string;
title: string;
totalCount: number;
successCount: number;
startDate: string;
endDate: string;
recordIds: number[];
};

export type ChallengeRecordDetailData = {
result: string;
data: {
id: 0;
createdAt: string;
content: string;
imageUrl: string;
};
message: string;
errorCode: string;
id: 0;
createdAt: string;
content: string;
imageUrl: string;
};

export type CompleteChallengeData = {
Expand Down
27 changes: 27 additions & 0 deletions src/assets/stamp-active.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/assets/stamp-inactive.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions src/components/common/challenge-title/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Text } from '@chakra-ui/react';
import styled from '@emotion/styled';

type ChallengeTitleProps = {
category: string;
title: string;
};

const ChallengeTitle = ({ category, title }: ChallengeTitleProps) => {
return (
<Wrapper>
<Text fontSize='var(--font-size-xs)' color='var(--color-green-01)'>
{category}
</Text>
<Text fontSize='var(--font-size-xl)' fontWeight='700'>
{title}
</Text>
</Wrapper>
);
};

export default ChallengeTitle;

const Wrapper = styled.div`
margin: 16px;
display: flex;
flex-direction: column;
text-align: left;
`;
5 changes: 4 additions & 1 deletion src/components/common/cta/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const CTA = ({ label, disabled, onClick }: CTAProps) => {

export default CTA;

export const CTA_CONTAINER_HEIGHT = '4rem';

const StyledCTA = styled.button<{ disabled?: boolean }>`
width: calc(100% - 16px); // 부모 요소의 좌우 padding 빼고
border: none;
Expand Down Expand Up @@ -53,7 +55,8 @@ export const CTAContainer = styled.div`
bottom: 0;
display: flex;
width: 100%;
height: 4rem;
height: ${CTA_CONTAINER_HEIGHT};
padding: 8px 16px;
background-color: var(--color-white);
z-index: 1;
`;
37 changes: 29 additions & 8 deletions src/components/common/form/textarea/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import { Text } from '@chakra-ui/react';
import styled from '@emotion/styled';

type TextareaProps = {
placeholder?: string;
value: string;
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
minValueLength?: number;
valid?: boolean;
};

const Textarea = ({ placeholder, value, onChange, valid }: TextareaProps) => {
const Textarea = ({
placeholder,
value,
onChange,
minValueLength,
valid,
}: TextareaProps) => {
return (
<StyledTextarea
placeholder={placeholder}
value={value}
onChange={onChange}
valid={valid}
/>
<>
<StyledTextarea
placeholder={placeholder}
value={value}
onChange={onChange}
valid={valid}
/>
{/* 최소 길이 제한 있을 때만 보이기 */}
{minValueLength && (
<Text
fontSize='var(--font-size-xs)'
color={valid ? `var(--color-grey-01)` : `var(--color-class-05)`}
textAlign='right'
margin='8px 16px 0'
>
{value.length} / 최소 {minValueLength}자
</Text>
)}
</>
);
};

Expand All @@ -29,10 +50,10 @@ const StyledTextarea = styled.textarea<{ valid?: boolean }>`
? 'var(--color-grey-02) 1px solid'
: 'var(--color-class-05) 1px solid'};
padding: 12px;
width: 100%;
height: 180px;
resize: none;
outline: none;
margin: 0 16px;

&::placeholder {
color: var(--color-grey-01);
Expand Down
9 changes: 5 additions & 4 deletions src/components/common/tabs/tab-panels/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@ export const TabPanel = ({ children, value, selectedIndex }: TabPanelProps) => {
};

export const StyledTabPanels = styled.div`
height: 100%;
width: 100%;
position: relative;
text-align: center;
display: flex;
flex-direction: column;
flex: 1;
`;

export const StyledTabPanel = styled.div<{
active: boolean;
}>`
display: ${(p) => (p.active ? 'flex' : 'none')};
font-size: 2rem;
flex-direction: column;
flex: 1;
width: 100%;
height: 100%;
justify-content: center;
font-size: 2rem;
`;
2 changes: 1 addition & 1 deletion src/components/features/layout/top-bar/page-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const PageBarLayout = styled(Box)<{
padding: 0.5rem;
gap: 1rem;
background-color: ${(props) => props.backgroundColor};
z-index: 1000;
z-index: 1;
position: sticky;
top: ${({ show }) => (show ? '0' : '-100px')};
transition: top 0.3s;
Expand Down
30 changes: 7 additions & 23 deletions src/pages/challenge-detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { RankingSection } from './ranking-section/';
import { ReviewSection } from './review-section/';
import { type ChallengeDetailData } from '@/apis/challenge-detail/challenge.detail.response';
import DefaultImage from '@/assets/Default-Image.svg';
import ChallengeTitle from '@/components/common/challenge-title';
import { Tabs, Tab } from '@/components/common/tabs';
import { TabPanels, TabPanel } from '@/components/common/tabs/tab-panels';
import TopBar from '@/components/features/layout/top-bar';
Expand Down Expand Up @@ -79,12 +80,12 @@ const ChallengeDetailPage = () => {
</DefaultImageMask>
)}
</ImageList>

<ChallengeTitleWrapper>
<Category>{formatCategory(data?.category)}</Category>
<Title>{data?.title}</Title>
</ChallengeTitleWrapper>

{data && (
<ChallengeTitle
category={formatCategory(data.category)}
title={data.title}
/>
)}
<Tabs selectedTab={activeTab} onChange={handleSelectedTab}>
{tabsList.map((t, index) => (
<Tab key={t.label} label={t.label} value={index} />
Expand Down Expand Up @@ -140,20 +141,3 @@ export const StyledDefaultImage = styled.img`
object-fit: cover;
opacity: 50%;
`;

export const ChallengeTitleWrapper = styled.div`
margin: 16px;
display: flex;
flex-direction: column;
text-align: left;
`;

export const Category = styled.div`
font-size: var(--font-size-xs);
color: var(--color-green-01);
`;

export const Title = styled.div`
font-size: var(--font-size-xl);
font-weight: bold;
`;
Loading