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

세부 목표 정하기 & 만다라트 완성 기능 #33

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
},
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"editor.tabSize": 2,
"cSpell.words": ["GOATANI", "Ohtani", "probrain", "Tani"],
"cSpell.words": ["embla", "GOATANI", "Ohtani", "probrain", "Tani"],
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
78 changes: 78 additions & 0 deletions src/app/create/complete/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use client';

import Button from '@/components/button';
import { MandalartCarousel } from '@/components/mandalart';
import { CREATE_POSTING_PATH } from '@/constants/path';
import useDidMount from '@/hooks/use-did-mount';
import { MandalartPartType } from '@/types/mandalart';
import { BranchesType, CreateStorageType, getCreateStorage } from '@/utils/storage';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import styled from 'styled-components';

function CreateCompletePage() {
const router = useRouter();

const [contents, setContents] = useState<MandalartPartType[]>([]);

const fullGoal = contents.length > 0 && contents[0].mainContent;

const initSetting = () => {
const data = getCreateStorage() as CreateStorageType;

if (data) {
const mainContent = {
mainContent: data['full-goal'],
subContents: data.branches.map(({ title }: BranchesType) => title),
};
const subContents = data.branches.map(({ title, details }: BranchesType) => ({
mainContent: title,
subContents: details,
}));
setContents([mainContent, ...subContents]);
}
};

useDidMount(initSetting);

return (
<div>
{/* TODO : 스켈레톤 추가 */}
<Heading>{fullGoal}</Heading>
<MandalartCarousel contents={contents} theme='primary' isFullMandalart />

<ButtonWrapper>
<Button onClick={() => router.push(CREATE_POSTING_PATH)}>피드에 공유하기</Button>

<Button variant='outline'>다운로드</Button>
</ButtonWrapper>
</div>
);
}

const Heading = styled.h1`
font-weight: 700;
font-size: 16px;
line-height: 22px;

text-align: center;

color: #000000;
text-decoration: underline;
text-underline-offset: 4px;

margin-top: 37px;
margin-bottom: 10px;
`;

const ButtonWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
gap: 10px;

max-width: 400px;
margin: 45px auto;
`;

export default CreateCompletePage;
106 changes: 106 additions & 0 deletions src/app/create/detailed-goals/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import Badge from '@/components/badge';
import Button from '@/components/button';
import { Input } from '@/components/input';
import React, { useState } from 'react';
import styled from 'styled-components';

interface TileInputProps {
initRecommendedContents: string[];

contents: string[];
isInputDisabled: boolean;

addSubContent: (content: string) => void | null;
}

function TileInput({ initRecommendedContents, addSubContent, contents, isInputDisabled }: TileInputProps) {
const [input, setInput] = useState('');

const recommendedContents = initRecommendedContents.filter((content) => !contents.includes(content)) ?? [];

const handleAddSubContent = () => {
if (input === '') return;

addSubContent(input);
setInput('');
};

const handleBadgeClick = (content: string) => {
const addResult = addSubContent(content);

if (addResult) {
setInput('');
}
};

const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
handleAddSubContent();
}
};

return (
<>
<InputWrapper>
<Input
type='text'
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={handleInputKeyDown}
inputSize='lg'
/>
<InputButtonWrapper>
<Button size='xs' onClick={handleAddSubContent} disabled={isInputDisabled}>
추가
</Button>
</InputButtonWrapper>
</InputWrapper>
<BadgeWrapper>
{recommendedContents.map((content, idx) => (
<Badge key={idx} onClick={() => handleBadgeClick(content)}>
{content}
</Badge>
))}
</BadgeWrapper>
</>
);
}

const InputWrapper = styled.div`
position: relative;
width: 100%;
`;

const BadgeWrapper = styled.div`
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
gap: 12px 10px;
width: 100%;

${({ theme }) => theme.typography.sm}
`;

const InputButtonWrapper = styled.div`
width: 50px;

position: absolute;
right: 7px;
top: 6px;
bottom: 6px;

margin: auto 0;
`;

const ButtonWrapper = styled.div`
position: absolute;
bottom: 0;
left: 0;
right: 0;

width: 100%;

padding: 20px;
`;

export default TileInput;
96 changes: 94 additions & 2 deletions src/app/create/detailed-goals/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,93 @@
'use client';

import TileInput from '@/app/create/detailed-goals/input';
import Heading from '@/app/create/heading';
import Button from '@/components/button';
import { MandalartCarousel } from '@/components/mandalart';
import { DUMMY_MANDALART_TOTAL } from '@/constants/mandalart';
import { INIT_CONTENTS } from '@/constants/mandalart';
import useDidMount from '@/hooks/use-did-mount';
import { MandalartPartType } from '@/types/mandalart';
import { DETAILED_GOAL, getCreateStorage, setCreateStorage } from '@/utils/storage';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import styled from 'styled-components';
const BADGE_DUMMY = ['몸 만들기', '돈 벌기', '취업', '취미', '여행', '책 읽기', '취미2', '여행2', '책 읽기2'];

export default function DetailedGoalsPage() {
const router = useRouter();
const completeCount = 0;
const [contents, setContents] = useState<MandalartPartType[]>(INIT_CONTENTS);
const [currentPart, setCurrentPart] = useState(0);

const isCurrentPartPullSelect = contents[currentPart].subContents.length === 8;
const currentPartContents = contents[currentPart].subContents;

const isAllSelect = contents.every((content) => content.subContents.length === 8);

const handleRemoveTileContent = (partIndex: number, tileIndex: number) => {
const newContents = [...contents];
newContents[currentPart].subContents.splice(tileIndex, 1);
setContents(newContents);
};

const handleTileClick = (partIndex: number, tileIndex: number) => {
if (partIndex !== currentPart) return;
handleRemoveTileContent(partIndex, tileIndex);
};

const handleAddTileContent = (content: string) => {
if (isCurrentPartPullSelect) return;

const newContents = [...contents];
newContents[currentPart].subContents.push(content);
setContents(newContents);
};

const onNextClick = () => {
setCreateStorage(DETAILED_GOAL, contents);
router.push('/create/complete');
};

const init_setting = () => {
const keyGoals = getCreateStorage('key-goal') as string[];

const newContents = keyGoals.map((content: string) => ({
mainContent: content,
subContents: [],
}));

setContents(newContents);
};

useDidMount(() => {
init_setting();
});

return (
<Wrapper>
<MandalartCarousel contents={DUMMY_MANDALART_TOTAL} theme='primary' />
<Heading>
세부 목표를 정해주세요! <br />
오타니 되기 까지 {60 + completeCount * 5}%
</Heading>

<MandalartCarousel
contents={contents}
theme='primary'
handleTileClick={handleTileClick}
handleCurrentPart={(partIndex) => setCurrentPart(partIndex)}
/>

<TileInput
initRecommendedContents={BADGE_DUMMY}
addSubContent={handleAddTileContent}
contents={currentPartContents}
isInputDisabled={isCurrentPartPullSelect}
/>
<ButtonWrapper>
<Button disabled={!isAllSelect} onClick={onNextClick}>
세부 목표 정하기
</Button>
</ButtonWrapper>
</Wrapper>
);
}
Expand All @@ -19,4 +99,16 @@ const Wrapper = styled.div`
gap: 20px;
position: relative;
color: black;
height: 100%;
`;

const ButtonWrapper = styled.div`
position: absolute;
bottom: 0;
left: 0;
right: 0;

width: 100%;

padding: 20px;
`;
20 changes: 8 additions & 12 deletions src/app/create/full-goals/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,12 @@
import Heading from '@/app/create/heading';
import Button from '@/components/button';
import { Input } from '@/components/input';
import { FULL_GOAL, setCreateStorage } from '@/utils/storage';
import { useRouter } from 'next/navigation';
import { ChangeEvent, useState } from 'react';
import styled from 'styled-components';

const list = [
'감자칩이되기',
'감자칩이되기',
'감자칩이되기',
'전병 먹기',
'전병 먹기',
'전병 먹기',
'전병민은 카톡을 읽어라',
'전병은 왜 카톡을 안읽냐',
'내 pr 확인해라',
];
const list = ['감자칩이되기', '감자칩이되기', '감자칩이되기', '전병 먹기', '전병 먹기', '전병 먹기'];

function FullGoalsPage() {
const router = useRouter();
Expand All @@ -32,6 +23,11 @@ function FullGoalsPage() {
setInput(e.target.value);
};

const nextClick = () => {
setCreateStorage(FULL_GOAL, input);
router.push('/create/key-goals');
};

return (
<div>
<Heading>
Expand All @@ -50,7 +46,7 @@ function FullGoalsPage() {
))}
</List>
<ButtonWrapper>
<Button onClick={() => router.push('/create/key-goals')}>핵심 목표 정하기</Button>
<Button onClick={nextClick}>핵심 목표 정하기</Button>
</ButtonWrapper>
</div>
);
Expand Down
Loading