Skip to content
Open
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
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,963 changes: 1,292 additions & 1,671 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 10 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
{
"name": "1-weekly-mission",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"web-vitals": "^2.1.4"
"devDependencies": {
"@types/react": "^18.2.46",
"@types/react-dom": "^18.2.18",
"file-loader": "^6.2.0",
"react-scripts": "^5.0.1",
"typescript": "^5.3.3",
"url-loader": "^4.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
"dependencies": {
"react-router-dom": "^6.20.0",
"styled-components": "^6.1.1"
},
"browserslist": {
"production": [
Expand All @@ -33,8 +28,5 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"react-scripts": "^5.0.1"
}
}
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>weekly mission</title>
<link href="../src/indexCss.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
Expand Down
Binary file added src/Image/_close.png
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 src/Image/add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
10 changes: 10 additions & 0 deletions src/Image/delete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
10 changes: 10 additions & 0 deletions src/Image/facebookBlue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
10 changes: 10 additions & 0 deletions src/Image/kakao.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions src/Image/kebab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/Image/link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
7 changes: 7 additions & 0 deletions src/Image/pen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
11 changes: 11 additions & 0 deletions src/Image/share.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/Image/star.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
11 changes: 11 additions & 0 deletions src/Image/urlLink.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
122 changes: 122 additions & 0 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useState, useEffect } from "react";
import logoIcon from "../Image/logo.svg";
import nullImg from "../Image/bulldog.png";
import StarImg from "../Image/star.svg";
import KebabImg from "../Image/kebab.svg";
import { formatDateString, calculateElapsedTime } from "./Time";
import * as S from "./Styled";
import { DeleteLink, AddToFolderModal } from "./modal";
import { LinkData } from "@utils/type";

function Card({ data }: { data: LinkData }) {
const formattedDate = formatDateString(data.created_at);
const [imgNull, setImgNull] = useState("");
const createdTime = calculateElapsedTime(data.created_at);
const [kebabBool, setKebabBool] = useState(false);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

더 좋은 변수명이 있을 것 같습니다.
변수명이 타입(bool)을 포함하도록 하는 건 좋은 습관이 아니에요.
정확히 어떤 역할을 하는 변수인지 잘 표현해주세요.

약간의 팁을 드리자면 boolean 타입의 변수들에 경우 is~, has~ 같은 prefix를 붙이면 의미를 나타내기 좋습니다.
kebabBool같은 경우 삭제, 폴더의 추가 등 여러 동작들을 노출할지를 결정하므로 isShowMoreActions이런 느낌으로 네이밍 해볼 수 있겠네요.

const [ago, setAgo] = useState("");
const [modalContent, setModalContent] = useState<string | null>(null);
const [modalOpen, setModalOpen] = useState(false);

const handleKebabClick = () => {
setKebabBool((prevBool) => !prevBool);
};

const setImageNull = () => {
if (data.image_source == undefined) {
setImgNull(nullImg);
} else {
setImgNull(data.image_source);
}
};

const calculateAgo = (createdTime: number) => {
if (createdTime < 2) {
return "1 minute ago";
} else if (createdTime <= 59) {
return `${createdTime} minutes ago`;
} else if (createdTime / 60 <= 23) {
return `${Math.ceil(createdTime / 60)} hour ago`;
} else if (createdTime / 60 >= 24 && createdTime / 60 / 24 < 2) {
return `1 day ago`;
} else if (createdTime / 60 / 24 >= 2 && createdTime / 60 / 24 <= 30) {
return `${Math.ceil(createdTime / 60 / 24)} days ago`;
} else if (createdTime / 60 / 24 > 30 && createdTime / 60 / 24 <= 60) {
return `1 month ago`;
} else if (createdTime / 60 / 24 > 60 && createdTime / 60 / 24 <= 365) {
return `${Math.ceil(createdTime / 60 / 24 / 30)} months ago`;
} else if (createdTime / 60 / 24 > 365 && createdTime / 60 / 24 <= 730) {
return `1 year ago`;
} else {
return `${Math.ceil(createdTime / 60 / 24 / 365)} years ago`;
}
};

useEffect(setImageNull, [data.image_source]);
useEffect(() => {
const ago = calculateAgo(createdTime);
setAgo(ago);
}, [createdTime]);
Comment on lines +54 to +58
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

useEffect에 넘기는 콜백을 따로 선언하는 경우도 있고 화살표함수로 바로 선언하는 경우도 있네요.
특별한 이유가 없다면 일관된 컨벤션으로 작성해주시면 좋을 듯 합니다.


const handleDeleteClick = () => {
setModalContent("DeleteLinkModal");
setModalOpen(true);
};

const handleAddToFolderClick = () => {
setModalContent("AddToFolderModal");
setModalOpen(true);
};

const handleCloseModal = () => {
setModalContent(null);
setModalOpen(false);
};

return (
<>
<S.Card>
<a href={`${data.url}`} target="_blank" rel="noopener noreferrer">
<S.CardImgWrap>
{data.image_source === undefined ? (
<>
<S.NullImg src={`${imgNull}`} alt={`${data.title}`}></S.NullImg>
<S.NullImg src={logoIcon} alt="logo"></S.NullImg>
</>
) : (
<S.CardImg src={`${imgNull}`} alt={`${data.title}`}></S.CardImg>
)}
</S.CardImgWrap>
</a>
<S.Star src={StarImg} alt="별 이미지" />
<S.CardText className="cardText">
<S.KebabAgoBox>
<S.Ago>{`${ago}`}</S.Ago>
<S.Kebab onClick={handleKebabClick}>
<img src={KebabImg} alt="케밥 이미지" />
</S.Kebab>
{kebabBool && (
<S.KebabSelect>
<S.kebabOption onClick={handleDeleteClick}>
삭제하기
</S.kebabOption>
<S.kebabOption onClick={handleAddToFolderClick}>
폴더에 추가
</S.kebabOption>
</S.KebabSelect>
)}
</S.KebabAgoBox>
<S.Des>{`${data.description}`}</S.Des>
<S.CardDate>{`${formattedDate}`}</S.CardDate>
</S.CardText>
</S.Card>
{modalOpen && modalContent === "DeleteLinkModal" && (
<DeleteLink onClose={handleCloseModal} />
)}
{modalOpen && modalContent === "AddToFolderModal" && (
<AddToFolderModal onClose={handleCloseModal} />
)}
</>
);
}

export default Card;
Loading