Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

[FE] feat: 발행 시 설정할 수 있는 정보 추가, 도움말 패널 닫기 기능 구현 #464

Merged
merged 23 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
39a8186
refactor: 글 발행 api medium, tistory로 분리
yogjin Sep 21, 2023
122bc9d
feat: 글 발행 medium, tistory 요청 타입 추가
yogjin Sep 21, 2023
5e9fc56
refactor: 사용하지 않는 발행 정보 타입 삭제
yogjin Sep 21, 2023
282953a
feat: 티스토리, 미디엄 발행 정보 탭 분리
yogjin Sep 21, 2023
cef304c
chore: 비밀번호, 발행, 시간 svg 추가
yogjin Sep 21, 2023
3a8a568
refactor: `Tags` -> `태그` 네이밍 변경
yogjin Sep 21, 2023
0b3fa15
style: 발행 정보 입력 탭 아이콘 추가 및 스타일링
yogjin Sep 21, 2023
37a781c
feat: `tistory` 발행 방식이 `보호` 일 때 비밀번호 input 나타나게 함
yogjin Sep 21, 2023
c219a20
feat: `dateFormatter` 형식 `HH:MM`, `'YYYY-MM-DD'` 추가
yogjin Sep 21, 2023
b065152
feat: `useOutsideClickEffect` 훅 추가
yogjin Sep 21, 2023
13535a3
feat: 발행 날짜, 시간 input 추가
yogjin Sep 21, 2023
7151e25
style: 발행 정보 칸 스타일 수정
yogjin Sep 21, 2023
a674924
feat: 발행 예약 값 넣기 위해 ref 설정
yogjin Sep 21, 2023
2a2f916
style: `WritingPropertySection` 스타일 수정
yogjin Sep 21, 2023
06a308f
fix: 미디엄 발행 방식 `onChange` select에 선언
yogjin Sep 21, 2023
356dc2f
feat: 티스토리 발행 `현재 | 예약` 버튼 추가
yogjin Sep 21, 2023
6c04923
fix: tistory 발행 예약시간 없을 시 `publishTime` 빈 문자열로 설정
yogjin Sep 21, 2023
3029661
refactor: `TODO` comment 제거
yogjin Sep 21, 2023
557b8a3
chore: `TODO: 카테고리 선택 기능` 주석 추가
yogjin Sep 21, 2023
d1694b1
style: 발행정보 태그 깨지는 스타일 수정
yogjin Sep 21, 2023
db2fa4f
chore: 주석 제거
yogjin Sep 21, 2023
8202df0
refactor: `Menu` 컴포넌트 `closeModal` prop 삭제
yogjin Sep 21, 2023
59986a8
feat: `useOutsideClickEffect` 이용해 도움말 패널 닫기 기능 구현
yogjin Sep 21, 2023
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
11 changes: 7 additions & 4 deletions frontend/src/apis/writings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import type {
GetDetailWritingsResponse,
GetWritingPropertiesResponse,
GetWritingResponse,
PublishWritingArgs,
UpdateWritingTitleArgs,
UpdateWritingOrderArgs,
GetHomeWritingsResponse,
PublishWritingToTistoryArgs,
PublishWritingToMediumArgs,
} from 'types/apis/writings';

// 글 생성(글 업로드): POST
Expand Down Expand Up @@ -38,9 +39,11 @@ export const getWriting = (writingId: number): Promise<GetWritingResponse> =>
export const getWritingProperties = (writingId: number): Promise<GetWritingPropertiesResponse> =>
http.get(`${writingURL}/${writingId}/properties`);

// 글 발행하기: POST
export const publishWriting = ({ writingId, body }: PublishWritingArgs) =>
http.post(`${writingURL}/${writingId}/publish`, { json: body });
export const publishWritingToTistory = ({ writingId, body }: PublishWritingToTistoryArgs) =>
http.post(`${writingURL}/${writingId}/publish/tistory`, { json: body });

export const publishWritingToMedium = ({ writingId, body }: PublishWritingToMediumArgs) =>
http.post(`${writingURL}/${writingId}/publish/medium`, { json: body });

// 카테고리 글 상세 목록 조회 : GET
export const getDetailWritings = (categoryId: number): Promise<GetDetailWritingsResponse> =>
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ export { ReactComponent as DonggleIcon } from './donggle-logo.svg';
export { ReactComponent as BlurBackgroundIcon } from './blur-background.svg';
export { ReactComponent as HyperlinkIcon } from './hyperlink.svg';
export { ReactComponent as HomeBorderIcon } from './home-border.svg';
export { ReactComponent as TimeIcon } from './time.svg';
export { ReactComponent as PasswordIcon } from './password.svg';
export { ReactComponent as PublishIcon } from './publish.svg';
12 changes: 12 additions & 0 deletions frontend/src/assets/icons/password.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 frontend/src/assets/icons/publish.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions frontend/src/assets/icons/time.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { css, styled } from 'styled-components';
import TagInput from '../@common/TagInput/TagInput';
import Button from '../@common/Button/Button';
import Spinner from 'components/@common/Spinner/Spinner';
import { LeftArrowHeadIcon, TagIcon } from 'assets/icons';
import { slideToLeft } from 'styles/animation';
import { TabKeys } from 'components/WritingSideBar/WritingSideBar';
import { useMediumPublishingPropertySection } from './useMediumPublishingPropertySection';
import { default as S } from './PublishingPropertyStyle';
import type { Blog } from 'types/domain';

type Props = {
writingId: number;
publishTo: Blog;
selectCurrentTab: (tabKey: TabKeys) => void;
};

enum MediumPublishStatus {
'PUBLIC' = 'Public',
'PRIVATE' = 'Draft',
'PROTECT' = 'Unlisted',
}

const MediumPublishStatusList = Object.keys(
MediumPublishStatus,
) as (keyof typeof MediumPublishStatus)[];

const MediumPublishingPropertySection = ({ writingId, publishTo, selectCurrentTab }: Props) => {
const { isLoading, setTags, setPublishStatus, publishWritingToMedium } =
useMediumPublishingPropertySection({
selectCurrentTab,
});

if (isLoading)
return (
<S.LoadingWrapper>
글을 발행하고 있어요
<Spinner />
</S.LoadingWrapper>
);

return (
<S.PublishingPropertySection $blog={publishTo}>
<S.SectionHeader>
<button
onClick={() => selectCurrentTab(TabKeys.Publishing)}
aria-label='발행 블로그 플랫폼 선택란으로 이동'
>
<LeftArrowHeadIcon width={14} height={14} />
</button>
발행 정보
</S.SectionHeader>
<S.Properties>
<S.PropertyRow>
<S.PropertyName>발행 방식</S.PropertyName>
<div>
<select
onChange={(e) => setPublishStatus(e.target.value as keyof typeof MediumPublishStatus)}
>
{MediumPublishStatusList.map((value, index) => (
<option key={index} value={value}>
{MediumPublishStatus[value]}
</option>
))}
</select>
</div>
</S.PropertyRow>
<S.PropertyRow>
<S.PropertyName>
<TagIcon width={12} height={12} />
태그
</S.PropertyName>
<div>
<TagInput onChangeTags={setTags} />
</div>
</S.PropertyRow>
</S.Properties>
<Button block variant='secondary' onClick={() => publishWritingToMedium(writingId)}>
발행하기
</Button>
</S.PublishingPropertySection>
);
};

export default MediumPublishingPropertySection;
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { Meta, StoryObj } from '@storybook/react';
import { StoryContainer } from 'styles/storybook';
import PublishingPropertySection from './PublishingPropertySection';
import MediumPublishingPropertySection from './MediumPublishingPropertySection';

const meta: Meta<typeof PublishingPropertySection> = {
const meta: Meta<typeof MediumPublishingPropertySection> = {
title: 'publishing/PublishingPropertySection',
component: PublishingPropertySection,
component: MediumPublishingPropertySection,
};

export default meta;
Expand All @@ -13,7 +13,11 @@ type Story = StoryObj<typeof meta>;
export const Primary: Story = {
render: () => (
<StoryContainer>
<PublishingPropertySection writingId={1} publishTo={'MEDIUM'} selectCurrentTab={() => {}} />
<MediumPublishingPropertySection
writingId={1}
publishTo={'MEDIUM'}
selectCurrentTab={() => {}}
/>
</StoryContainer>
),
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { css, styled } from 'styled-components';
import { slideToLeft } from 'styles/animation';
import { Blog } from 'types/domain';

const PublishingPropertyStyle = {
PublishingPropertySection: styled.section<{ $blog: Blog }>`
display: flex;
flex-direction: column;
gap: 2rem;
animation: ${slideToLeft} 0.5s;

${({ theme, $blog }) => css`
& > button {
outline-color: ${theme.color[$blog.toLowerCase()]};
background-color: ${theme.color[$blog.toLowerCase()]};

&:hover {
background-color: ${theme.color[$blog.toLowerCase()]};
}
}
`};
`,
SectionHeader: styled.h1`
display: flex;
gap: 1.5rem;
font-size: 1.5rem;
font-weight: 700;
line-height: 1.5rem;
`,
Properties: styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
padding: 0 0 1rem 0.9rem;
`,
PropertyRow: styled.div`
display: flex;
align-items: center;

select,
input {
padding: 0.6rem;
}
`,
PropertyName: styled.div`
display: flex;
align-items: center;
gap: 0.6rem;
flex-shrink: 0;
width: 9.5rem;
color: ${({ theme }) => theme.color.gray8};
font-size: 1.3rem;
font-weight: 600;
`,
LoadingWrapper: styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4rem;
font-size: 1.3rem;
`,
PublishTimeInputContainer: styled.div`
display: flex;
flex-direction: column;
gap: 0.4rem;
`,
PublishButtonContainer: styled.div`
display: flex;
align-items: center;
gap: 0.6rem;
`,
PublishButton: styled.button<{ selected: boolean }>`
color: ${({ theme, selected }) => !selected && theme.color.gray5};
`,
PublishButtonAndTimeInputContainer: styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
`,
};

export default PublishingPropertyStyle;
Loading
Loading