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

[안성재] Week14 #517

Merged
merged 16 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
f3d10f6
chore: fetch 함수 네이밍 수정
asusia1111 Dec 8, 2023
5d032c1
chore: IntersectionObserver 내부 조건문 간결화
asusia1111 Dec 8, 2023
620e69d
refactor: 이벤트 핸들러 인라인 함수 최대한 사용하지 않도록 수정
asusia1111 Dec 8, 2023
0308a1d
refactor: 카드 리스트 컴포넌트 early return 사용하도록 수정
asusia1111 Dec 8, 2023
920bb6f
refactor: 옵셔널 체이닝 사용하지 않도록 수정
asusia1111 Dec 8, 2023
641895f
feat: 로그인, 회원가입 페이지 1차 구현
asusia1111 Dec 9, 2023
8630817
chore: react-hook-form 설치
asusia1111 Dec 9, 2023
91a1187
feat: 로그인 페이지 react-hook-form을 사용해서 구현
asusia1111 Dec 9, 2023
3a06e3d
feat: 회원가입 페이지 react-hook-form을 사용해서 구현, accessToken을 저장하고 사용하도록 기능 추가
asusia1111 Dec 9, 2023
df87075
feat: 비밀번호와 비밀번호 확인의 일치 여부를 입력값이 변할 때마다 확인하도록 추가
asusia1111 Dec 9, 2023
c675d97
feat: 정규식 상수 utils 디렉토리의 regex 파일로 분리
asusia1111 Dec 9, 2023
c8358cc
refactor: 함수 컴포넌트 화살표 함수 방식으로 변경
asusia1111 Dec 9, 2023
211f507
feat: HTML로 작성된 기존 랜딩 페이지 마이그레이션
asusia1111 Dec 9, 2023
189c495
feat: Nav 컴포넌트에서 데이터 페칭하지 않고 페이지 컴포넌트에서 prop으로 받도록 로직 수정
asusia1111 Dec 10, 2023
0cf3299
refactor: JSX 코드에서 && 연산자 삼항 연산자로 수정
asusia1111 Dec 10, 2023
c66ecff
chore: API 주소 환경 변수로 설정
asusia1111 Dec 10, 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
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,4 @@ yarn-error.log*
next-env.d.ts

# spell
cspell.json

# signin
src/pages/signin.tsx
cspell.json
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"next": "13.5.6",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.48.2",
"react-tiny-popover": "^8.0.4",
"styled-components": "^6.1.1",
"timeago": "^1.6.7",
Expand Down
Binary file added public/assets/images/screenshot/hero.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/screenshot/image1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/screenshot/image2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/screenshot/image3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/screenshot/image4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/api/fetch.ts → src/api/apiRequest.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import axios, { AxiosRequestConfig } from 'axios';

const api = axios.create({
baseURL: 'https://bootcamp-api.codeit.kr/api/',
baseURL: process.env.NEXT_PUBLIC_BASE_URL,
});

const fetch = async (options: AxiosRequestConfig) => {
const apiRequest = async (options: AxiosRequestConfig) => {
const response = await api({ ...options });
return response;
};

export default fetch;
export default apiRequest;
10 changes: 3 additions & 7 deletions src/components/AddLinkForm/AddLinkForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface Props {
isScrolled: boolean;
}

function AddLinkForm({ isScrolled }: Props) {
const AddLinkForm = ({ isScrolled }: Props) => {
const [value, setValue] = useState('');
const [showFooter, setShowFooter] = useState(false);
const footerRef = useContext(FooterRefContext);
Expand All @@ -18,11 +18,7 @@ function AddLinkForm({ isScrolled }: Props) {

useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
setShowFooter(true);
} else {
setShowFooter(false);
}
setShowFooter(entry.isIntersecting);
});

const currentRef = footerRef?.current;
Expand Down Expand Up @@ -53,6 +49,6 @@ function AddLinkForm({ isScrolled }: Props) {
</S.Form>
</S.FormContainer>
);
}
};

export default AddLinkForm;
75 changes: 42 additions & 33 deletions src/components/CardList/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as S from './Card.style';
import { formatDate, formatTimeDiff } from '@utils/format';
import { Popover } from 'react-tiny-popover';
import { MouseEvent, useState } from 'react';
import { MouseEvent, useCallback, useState } from 'react';
import Modal from '@components/Modal';
import ModalDeleteLink from '@components/Modal/ModalDeleteLink';
import ModalAddLink from '@components/Modal/ModalAddLink';
Expand All @@ -15,7 +15,7 @@ interface Props {
item: Data;
}

function Card({ folders, item }: Props) {
const Card = ({ folders, item }: Props) => {
const [popoverIsOpen, setPopoverIsOpen] = useState(false);
const [modalDeleteLinkIsOpen, setModalDeleteLinkIsOpen] = useState(false);
const [modalAddLinkIsOpen, setModalAddLinkIsOpen] = useState(false);
Expand All @@ -24,6 +24,35 @@ function Card({ folders, item }: Props) {
const timeDiff = formatTimeDiff(created_at);
const date = formatDate(created_at);

const handleOpenPopover = useCallback((e: MouseEvent) => {
e.preventDefault();
setPopoverIsOpen(!popoverIsOpen);
}, []);

const handleClosePopover = useCallback(() => {
setPopoverIsOpen(false);
}, []);

const handleOpenModalDeleteLink = useCallback((e: MouseEvent) => {
e.preventDefault();
setModalDeleteLinkIsOpen(true);
}, []);

const handleCloseModalDeleteLink = useCallback((e: MouseEvent) => {
e.preventDefault();
setModalDeleteLinkIsOpen(false);
}, []);

const handleOpenModalAddLink = useCallback((e: MouseEvent) => {
e.preventDefault();
setModalAddLinkIsOpen(true);
}, []);

const handleCloseModalAddLink = useCallback((e: MouseEvent) => {
e.preventDefault();
setModalAddLinkIsOpen(false);
}, []);
Comment on lines +27 to +54
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커스텀 훅으로 분리하면 좀 더 UI에 집중할 수 있는 컴포넌트가 될 것 같네요!


return (
<Link href={url} target='_blank' rel='noopener noreferrer'>
<S.ImageContainer>
Expand All @@ -40,48 +69,28 @@ function Card({ folders, item }: Props) {
<Popover
isOpen={popoverIsOpen}
positions={'bottom'}
onClickOutside={() => setPopoverIsOpen(false)}
onClickOutside={handleClosePopover}
content={
<S.PopoverContainer>
<S.PopoverButton
onClick={(e) => {
e.preventDefault();
setModalDeleteLinkIsOpen(true);
}}>
<S.PopoverButton onClick={handleOpenModalDeleteLink}>
삭제하기
</S.PopoverButton>
{modalDeleteLinkIsOpen && (
<Modal
close={(e: MouseEvent) => {
e.preventDefault();
setModalDeleteLinkIsOpen(false);
}}>
{modalDeleteLinkIsOpen ? (
<Modal close={handleCloseModalDeleteLink}>
<ModalDeleteLink url={url} />
</Modal>
)}
<S.PopoverButton
onClick={(e) => {
e.preventDefault();
setModalAddLinkIsOpen(true);
}}>
) : null}
<S.PopoverButton onClick={handleOpenModalAddLink}>
폴더에 추가
</S.PopoverButton>
{modalAddLinkIsOpen && (
<Modal
close={(e: MouseEvent) => {
e.preventDefault();
setModalAddLinkIsOpen(false);
}}>
{modalAddLinkIsOpen ? (
<Modal close={handleCloseModalAddLink}>
<ModalAddLink folders={folders} url={url} />
</Modal>
)}
) : null}
</S.PopoverContainer>
}>
<S.KebabButton
onClick={(e: MouseEvent) => {
e.preventDefault();
setPopoverIsOpen(!popoverIsOpen);
}}>
<S.KebabButton onClick={handleOpenPopover}>
<img src='/assets/images/kebab.svg' alt='케밥 버튼' />
</S.KebabButton>
</Popover>
Expand All @@ -91,6 +100,6 @@ function Card({ folders, item }: Props) {
</S.Info>
</Link>
);
}
};

export default Card;
30 changes: 13 additions & 17 deletions src/components/CardList/CardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Props {
searchKeyword: string;
}

function CardList({ folders, items, searchKeyword }: Props) {
const CardList = ({ folders, items, searchKeyword }: Props) => {
const lowerCaseKeyword = searchKeyword.toLowerCase();

const filteredItems = useMemo(
Expand All @@ -23,23 +23,19 @@ function CardList({ folders, items, searchKeyword }: Props) {
[items, lowerCaseKeyword]
);

if (!filteredItems?.length) {
return <S.NoLink>저장된 링크가 없습니다</S.NoLink>;
}

return (
<>
{!filteredItems?.length ? (
<S.NoLink>저장된 링크가 없습니다</S.NoLink>
) : (
filteredItems && (
<S.CardListContainer>
{filteredItems.map((item) => (
<S.CardContainer key={item.id}>
<Card folders={folders} item={item} />
</S.CardContainer>
))}
</S.CardListContainer>
)
)}
</>
<S.CardListContainer>
{filteredItems.map((item) => (
<S.CardContainer key={item.id}>
<Card folders={folders} item={item} />
</S.CardContainer>
))}
</S.CardListContainer>
);
}
};

export default CardList;
16 changes: 8 additions & 8 deletions src/components/CurrentFolderInfo/CurrentFolderInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Props {
selectedId: string | undefined;
}

function CurrentFolderInfo({ selectedName, selectedId }: Props) {
const CurrentFolderInfo = ({ selectedName, selectedId }: Props) => {
const [modalShareIsOpen, setModalShareIsOpen] = useState(false);
const [modalEditIsOpen, setModalEditIsOpen] = useState(false);
const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
Expand All @@ -23,32 +23,32 @@ function CurrentFolderInfo({ selectedName, selectedId }: Props) {
<img src='/assets/images/share.svg' alt='공유 아이콘' />
<span>공유</span>
</button>
{modalShareIsOpen && (
{modalShareIsOpen ? (
<Modal close={() => setModalShareIsOpen(false)}>
<ModalShare folderName={selectedName} folderId={selectedId} />
</Modal>
)}
) : null}
<button onClick={() => setModalEditIsOpen(true)}>
<img src='/assets/images/name-change.svg' alt='이름 변경 아이콘' />
<span>이름 변경</span>
</button>
{modalEditIsOpen && (
{modalEditIsOpen ? (
<Modal close={() => setModalEditIsOpen(false)}>
<ModalEdit folderName={selectedName} />
</Modal>
)}
) : null}
<button onClick={() => setModalDeleteIsOpen(true)}>
<img src='/assets/images/delete.svg' alt='삭제 아이콘' />
<span>삭제</span>
</button>
{modalDeleteIsOpen && (
{modalDeleteIsOpen ? (
<Modal close={() => setModalDeleteIsOpen(false)}>
<ModalDelete folderName={selectedName} />
</Modal>
)}
) : null}
</S.OptionContainer>
</S.Container>
);
}
};

export default CurrentFolderInfo;
10 changes: 4 additions & 6 deletions src/components/FolderInfo/FolderInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ interface Props {
folder: Folder;
}

function FolderInfo({ folder }: Props) {
const folderName = folder?.name;
const owner = folder?.owner;
const ownerName = owner?.name;
const ownerProfileImg = owner?.profileImageSource;
const FolderInfo = ({ folder }: Props) => {
const { name: folderName } = folder;
const { name: ownerName, profileImageSource: ownerProfileImg } = folder.owner;

return (
<S.Container>
Expand All @@ -18,6 +16,6 @@ function FolderInfo({ folder }: Props) {
<S.H1>{folderName}</S.H1>
</S.Container>
);
}
};

export default FolderInfo;
Loading