Skip to content

Commit

Permalink
Merge pull request #87 from Neogasogaeseo/feat/#48
Browse files Browse the repository at this point in the history
  • Loading branch information
SeojinSeojin authored Jan 17, 2022
2 parents fa6d26b + bb1a0ff commit 9997126
Show file tree
Hide file tree
Showing 24 changed files with 570 additions and 2 deletions.
19 changes: 19 additions & 0 deletions src/application/stores/neososeo-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NeososeoAnswerData, NeososeoFormData } from '@api/types/neososeo-form';
import { atom } from 'recoil';

export const neososeoFormState = atom<NeososeoFormData | null>({
key: 'neososeoFormState',
default: null,
});

export const neososeoAnswerState = atom<NeososeoAnswerData>({
key: 'neososeoAnswerState',
default: {
userID: 0,
formID: 0,
name: '',
relationID: 0,
answer: '',
keyword: [],
},
});
2 changes: 2 additions & 0 deletions src/application/utils/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const isAllFilled = (...args: unknown[]) =>
args.every((arg) => arg !== null && arg !== undefined && arg !== '');
37 changes: 37 additions & 0 deletions src/assets/images/img_answerdone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/images/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as imgLogo } from './img_logo.svg';
export { default as imgEmptyProfile } from './img_empty_profile.svg';
export { default as imgEmptyJoinProfile } from './img_empty_join.svg';
export { ReactComponent as ImgTeamAdd } from './img_team_add.svg';
export { ReactComponent as ImgAnswerDone } from './img_answerdone.svg';
6 changes: 5 additions & 1 deletion src/infrastructure/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { neogaDataMock } from '../mock/neoga';
import { neososeoFormDataMock } from '../mock/neososeo-form';
import { teamDataMock } from '../mock/team';
import { userDataMock } from '../mock/user';
import { NeogaService } from './neoga';
import { NeososeoFormService } from './neososeo-form';
import { TeamService } from './team';
import { UserService } from './user';

Expand All @@ -15,12 +17,14 @@ function provideMockAPIService(): APIService {
const teamService = teamDataMock();
const userService = userDataMock();
const neogaService = neogaDataMock();
const neososeoFormService = neososeoFormDataMock();

return { teamService, userService, neogaService };
return { teamService, userService, neogaService, neososeoFormService };
}

export interface APIService {
teamService: TeamService;
userService: UserService;
neogaService: NeogaService;
neososeoFormService: NeososeoFormService;
}
6 changes: 6 additions & 0 deletions src/infrastructure/api/neososeo-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { NeososeoAnswerData, NeososeoFormData } from './types/neososeo-form';

export interface NeososeoFormService {
getFormInfo(userID: string, formID: string): Promise<NeososeoFormData>;
postFormAnswer(body: NeososeoAnswerData): Promise<{ isSuccess: boolean }>;
}
23 changes: 23 additions & 0 deletions src/infrastructure/api/types/neososeo-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export type Relation = {
id: number;
content: string;
};

export type NeososeoFormData = {
title: string;
content: string;
imageSub: string;
relation: Relation[];
userName: string;
userID: number;
formID: number;
};

export type NeososeoAnswerData = {
userID: number;
formID: number;
name: string;
relationID: number;
answer: string;
keyword: string[];
};
19 changes: 19 additions & 0 deletions src/infrastructure/mock/neososeo-form.data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NeososeoFormData } from '@api/types/neososeo-form';

export const NEOSOSEO_FORM_DATA: { FORM: NeososeoFormData } = {
FORM: {
title: '너가 닮고 싶은\n나의 일잘러 모습',
content: '나와 함께하며 당신이 닮고 싶었던 능력이 있었나요?',
relation: [
{ id: 1, content: '동네친구' },
{ id: 2, content: '쿵짝최고' },
{ id: 3, content: '존경해요' },
{ id: 4, content: '찐친베프' },
],
imageSub:
'https://ww.namu.la/s/61e3a8075b5aa238383c0d89badd3442f7389a0285575fc5bc5c16d2a34f22c66e57e35d568b63b706fa24750c784d55e972ceeea93fa5a91d00dab1eea37681e189ae826afe668fb379b0cb3a446f3268755691ed20c6a165185d44e2fd1029896062ed4df01a806594e35a637b2372',
userName: '강쥐',
userID: 1,
formID: 1,
},
};
20 changes: 20 additions & 0 deletions src/infrastructure/mock/neososeo-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NeososeoFormService } from '@api/neososeo-form';
import { NeososeoAnswerData } from '@api/types/neososeo-form';
import { NEOSOSEO_FORM_DATA } from './neososeo-form.data';

export function neososeoFormDataMock(): NeososeoFormService {
const getFormInfo = async () => {
await wait(2000);
return NEOSOSEO_FORM_DATA.FORM;
};

const postFormAnswer = async (body: NeososeoAnswerData) => {
console.log(body);
await wait(2000);
return { isSuccess: true };
};

return { getFormInfo, postFormAnswer };
}

const wait = (milliSeconds: number) => new Promise((resolve) => setTimeout(resolve, milliSeconds));
21 changes: 21 additions & 0 deletions src/presentation/components/common/NeososeoFormHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { StNeososeoFormHeader } from './style';

interface NeososeoFormHeaderProps {
title: string;
image: string;
}

function NeososeoFormHeader(props: NeososeoFormHeaderProps) {
const { title, image } = props;
return (
<StNeososeoFormHeader>
<div>{title}</div>
<div>
<img src={image} alt={title} />
</div>
</StNeososeoFormHeader>
);
}

export default NeososeoFormHeader;
23 changes: 23 additions & 0 deletions src/presentation/components/common/NeososeoFormHeader/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { COLOR } from '@styles/common/color';
import { FONT_STYLES } from '@styles/common/font-style';
import styled from 'styled-components';

export const StNeososeoFormHeader = styled.div`
width: 100vw;
display: grid;
grid-template-columns: auto 68px;
white-space: pre;
padding: 0 20px;
& div {
line-height: 33px;
${FONT_STYLES.SB_22_BODY}
}
& img {
width: 68px;
height: 68px;
border-radius: 34px;
background-color: ${COLOR.GRAY_1};
}
`;
81 changes: 81 additions & 0 deletions src/presentation/pages/NeososeoForm/Answer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { api } from '@api/index';
import { Keyword } from '@api/types/user';
import CommonInput from '@components/common/CommonInput';
import ImmutableKeywordList from '@components/common/Keyword/ImmutableList';
import { neososeoAnswerState, neososeoFormState } from '@stores/neososeo-form';
import { isAllFilled } from '@utils/string';
import { useEffect, useState } from 'react';
import { Link, Outlet, useNavigate } from 'react-router-dom';
import { useRecoilState, useRecoilValue } from 'recoil';
import { StButton, StNeososeoFormLayout, StNeososeoTitle, StSubTitle } from '../style';
import { StTextarea, StKeywordListWrapper } from './style';

function NeososeoFormAnswer() {
const neososeoFormData = useRecoilValue(neososeoFormState);
const [keywordList, setKeywordList] = useState<Keyword[]>([]);
const [neososeoAnswer, setNeososeoAnswer] = useRecoilState(neososeoAnswerState);
const navigate = useNavigate();

const postNeososeoForm = async () => {
const response = await api.neososeoFormService.postFormAnswer(neososeoAnswer);
if (response.isSuccess) navigate('../finish');
};

const setAnswer = (answer: string) => setNeososeoAnswer((prev) => ({ ...prev, answer }));

useEffect(() => {
setNeososeoAnswer((prev) => ({ ...prev, keyword: keywordList.map((k) => k.id) }));
}, [keywordList]);

if (!neososeoFormData) return <></>;

return (
<>
<StNeososeoFormLayout>
<div>
<StNeososeoTitle>
<span>Q.</span>
<span>{neososeoFormData.content}</span>
</StNeososeoTitle>
<StSubTitle>답변 내용을 입력해주세요.</StSubTitle>
<StTextarea placeholder="직접 입력해주세요" onChange={(e) => setAnswer(e.target.value)} />
<StSubTitle>키워드를 입력해주세요.</StSubTitle>
<Link to="keyword">
<CommonInput
width="100%"
placeholder="팀원을 표현하는 키워드를 입력해주세요."
disabled
/>
</Link>
<StKeywordListWrapper>
<ImmutableKeywordList keywordList={keywordList} onItemClick={() => null} />
</StKeywordListWrapper>
</div>
<StButton
disabled={!isAllFilled(neososeoAnswer.answer) || !(neososeoAnswer.keyword.length !== 0)}
onClick={postNeososeoForm}
>
답변 작성하기
</StButton>
</StNeososeoFormLayout>
<Outlet
context={{
keywordList: keywordList,
addKeyword: (keyword: Keyword) =>
setKeywordList((prev) =>
prev.map((prev) => prev.content).includes(keyword.content)
? prev
: [...prev, keyword],
),
removeKeyword: (targetKeyword: Keyword) =>
setKeywordList((prev) =>
prev.filter((keyword) => keyword.content !== targetKeyword.content),
),
targetUser: neososeoFormData.userID,
}}
/>
</>
);
}

export default NeososeoFormAnswer;
13 changes: 13 additions & 0 deletions src/presentation/pages/NeososeoForm/Answer/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { COMMON_INPUT } from '@styles/common/input';
import styled from 'styled-components';

export const StTextarea = styled.textarea`
${COMMON_INPUT}
width: 100%;
resize: unset;
height: 104px;
`;

export const StKeywordListWrapper = styled.div`
margin-top: 18px;
`;
21 changes: 21 additions & 0 deletions src/presentation/pages/NeososeoForm/Finish/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ImgAnswerDone } from '@assets/images';
import { useNavigate } from 'react-router-dom';
import { StButton } from '../style';
import { StBody, StNeososeoFinish } from './style';

function NeososeoFormFinish() {
const navigate = useNavigate();

return (
<StNeososeoFinish>
<StBody>
<ImgAnswerDone />
<div>답변이 전달되었어요</div>
<div>너가소개서, 좀 더 둘러보실래요?</div>
</StBody>
<StButton onClick={() => navigate('/')}>서비스 둘러보기</StButton>
</StNeososeoFinish>
);
}

export default NeososeoFormFinish;
33 changes: 33 additions & 0 deletions src/presentation/pages/NeososeoForm/Finish/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { COLOR } from '@styles/common/color';
import { FONT_STYLES } from '@styles/common/font-style';
import styled from 'styled-components';

export const StBody = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`;

export const StNeososeoFinish = styled.div`
height: 100vh;
width: 100vw;
padding: 50px 20px;
display: grid;
grid-template-rows: auto 58px;
& > div:nth-child(1) {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-bottom: 52px;
& > div:nth-child(2) {
color: ${COLOR.GRAY_8};
${FONT_STYLES.SB_20_TITLE}
}
& > div:nth-child(3) {
margin-top: 8px;
color: ${COLOR.GRAY_5};
${FONT_STYLES.R_15_TITLE}
}
}
`;
22 changes: 22 additions & 0 deletions src/presentation/pages/NeososeoForm/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { neososeoFormState } from '@stores/neososeo-form';
import { useNavigate } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { StButton } from '../style';
import { StNeososeoFormHome } from './style';

function NeososeoFormHome() {
const neososeoFormData = useRecoilValue(neososeoFormState);
const navigate = useNavigate();

if (!neososeoFormData) return <></>;
return (
<StNeososeoFormHome>
<div>
<div>{neososeoFormData.content}</div>
</div>
<StButton onClick={() => navigate('intro')}>답변 작성하기</StButton>
</StNeososeoFormHome>
);
}

export default NeososeoFormHome;
Loading

0 comments on commit 9997126

Please sign in to comment.