From 5fc5ebfc23bc18d67fb130768c6c3cc3b5afef23 Mon Sep 17 00:00:00 2001 From: Sugyo-In Date: Sun, 9 Jul 2023 15:27:54 +0900 Subject: [PATCH 001/132] fix: user name validation message --- src/containers/register/RegisterFormContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/register/RegisterFormContainer.tsx b/src/containers/register/RegisterFormContainer.tsx index 3541c691..ddde94ab 100644 --- a/src/containers/register/RegisterFormContainer.tsx +++ b/src/containers/register/RegisterFormContainer.tsx @@ -76,7 +76,7 @@ const RegisterFormContainer: React.FC = ({ }, username: (text: string) => { if (!/^[a-z0-9-_]{3,16}$/.test(text)) { - return '아이디는 3~16자의 알파벳,숫자,혹은 - _ 으로 이루어져야 합니다.'; + return '아이디는 3~16자의 알파벳 소문자,숫자,혹은 - _ 으로 이루어져야 합니다.'; } }, shortBio: (text: string) => { From bad2b6cbc403ab258b7d4bfdd9278f1d2d57a39e Mon Sep 17 00:00:00 2001 From: carrick Date: Mon, 10 Jul 2023 00:34:56 +0900 Subject: [PATCH 002/132] feat: handle port number --- .env | 4 +++- src/components/auth/AuthSocialButton.tsx | 2 +- src/index.server.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 7229cfaf..789d2684 100644 --- a/.env +++ b/.env @@ -1,4 +1,6 @@ -REACT_APP_API_HOST=http://localhost:5001/ PUBLIC_URL=/ + +REACT_APP_API_HOST=http://localhost:5002/ + REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/ REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file diff --git a/src/components/auth/AuthSocialButton.tsx b/src/components/auth/AuthSocialButton.tsx index bb0117a1..e5ae4510 100644 --- a/src/components/auth/AuthSocialButton.tsx +++ b/src/components/auth/AuthSocialButton.tsx @@ -62,7 +62,7 @@ const AuthSocialButton: React.FC = ({ const host = process.env.NODE_ENV === 'production' ? process.env.REACT_APP_API_HOST - : 'http://localhost:5001/'; + : 'http://localhost:5002/'; const redirectTo = `${host}api/v2/auth/social/redirect/${provider}?next=${currentPath}&isIntegrate=${ isIntegrate ? 1 : 0 diff --git a/src/index.server.ts b/src/index.server.ts index f04909c0..37cbb20d 100644 --- a/src/index.server.ts +++ b/src/index.server.ts @@ -17,7 +17,7 @@ app.use( ); const proxyMiddleware = proxy( - process.env.REACT_APP_API_HOST ?? 'http://localhost:5001/', + process.env.REACT_APP_API_HOST ?? 'http://localhost:5002/', {}, ); From 7c8a8a60b177fabfe93a011c976378f170f6c741 Mon Sep 17 00:00:00 2001 From: carrick Date: Fri, 14 Jul 2023 12:48:52 +0900 Subject: [PATCH 003/132] feat: add Vlink --- .env | 2 ++ src/components/base/HeaderLogo.tsx | 7 ++++--- src/components/common/RoundButton.tsx | 18 +++++++++++++++++- src/components/common/VLink.tsx | 25 +++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/components/common/VLink.tsx diff --git a/.env b/.env index 789d2684..97223465 100644 --- a/.env +++ b/.env @@ -1,5 +1,7 @@ PUBLIC_URL=/ +REACT_APP_CLIENT_V3_HOST=http://localhost:3001 + REACT_APP_API_HOST=http://localhost:5002/ REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/ diff --git a/src/components/base/HeaderLogo.tsx b/src/components/base/HeaderLogo.tsx index b05e265b..eda27adb 100644 --- a/src/components/base/HeaderLogo.tsx +++ b/src/components/base/HeaderLogo.tsx @@ -7,6 +7,7 @@ import { themedPalette } from '../../lib/styles/themes'; import { createFallbackTitle } from '../../lib/utils'; import media from '../../lib/styles/media'; import { ellipsis } from '../../lib/styles/utils'; +import VLink from '../common/VLink'; export interface HeaderLogoProps { custom: boolean; @@ -22,9 +23,9 @@ const HeaderLogo: React.FC = ({ if (!custom) { return ( - + - + ); } @@ -74,7 +75,7 @@ const HeaderLogoBlock = styled.div` } `; -const VelogLogoLink = styled(Link)` +const VelogLogoLink = styled(VLink)` color: inherit; svg { diff --git a/src/components/common/RoundButton.tsx b/src/components/common/RoundButton.tsx index eae19f8b..07ebd429 100644 --- a/src/components/common/RoundButton.tsx +++ b/src/components/common/RoundButton.tsx @@ -3,6 +3,7 @@ import styled, { css } from 'styled-components'; import { buttonColorMap } from '../../lib/styles/palette'; import { Route } from 'react-router'; import { themedPalette } from '../../lib/styles/themes'; +import VLink from './VLink'; type ButtonSize = 'SMALL' | 'DEFAULT' | 'LARGE'; @@ -102,9 +103,17 @@ const RoundButton: React.FC = ({ color = 'teal', size = 'DEFAULT', border = false, + children, ...rest }) => { if (to) { + if (to === '/') { + return ( + + {children} + + ); + } return ( ( @@ -116,6 +125,7 @@ const RoundButton: React.FC = ({ }} size={size} border={border} + children={children} {...rest} /> )} @@ -123,7 +133,13 @@ const RoundButton: React.FC = ({ ); } return ( - + ); }; diff --git a/src/components/common/VLink.tsx b/src/components/common/VLink.tsx new file mode 100644 index 00000000..d4c3d9df --- /dev/null +++ b/src/components/common/VLink.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import styled from 'styled-components'; + +type Props = { + to: string; + className?: string; + children?: React.ReactNode; + style?: React.CSSProperties; +}; + +function VLink({ to, children, className = '', style }: Props) { + const url = `${process.env.REACT_APP_CLIENT_V3_HOST}${to}`; + return ( + + {children} + + ); +} + +const Link = styled.a` + color: inherit; + text-decoration: none; +`; + +export default VLink; From be404b2919dccf8ef8e5fbf1ffa713daf277936a Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 23 Aug 2023 18:32:31 +0900 Subject: [PATCH 004/132] feat: add redirect to V3 client host in main page --- src/pages/home/HomePage.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx index 7e83d262..dae68c44 100644 --- a/src/pages/home/HomePage.tsx +++ b/src/pages/home/HomePage.tsx @@ -12,6 +12,9 @@ import FloatingHeader from '../../components/base/FloatingHeader'; export type HomePageProps = {}; function HomePage(props: HomePageProps) { + if (process.env.NODE_ENV === 'production') { + window.location.href = process.env.REACT_APP_CLIENT_V3_HOST!; + } return (
From 9b7090805ceb55779f3cecf32e37d54060fedd7e Mon Sep 17 00:00:00 2001 From: velopert Date: Mon, 28 Aug 2023 23:45:22 +0900 Subject: [PATCH 005/132] fix: apply ga4 --- public/index.html | 6 +++--- src/containers/base/Core.tsx | 2 +- src/server/Html.tsx | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/public/index.html b/public/index.html index b85e088d..9530b7b3 100644 --- a/public/index.html +++ b/public/index.html @@ -29,14 +29,14 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - - + + diff --git a/src/containers/base/Core.tsx b/src/containers/base/Core.tsx index 44cdbedc..0daacf4b 100644 --- a/src/containers/base/Core.tsx +++ b/src/containers/base/Core.tsx @@ -31,7 +31,7 @@ const Core: React.FC = ({ layer }) => { // adds setTimeout for page title sync // is there any better solution? setTimeout(() => { - gtag('config', 'UA-125599395-1', { + gtag('config', 'G-8D0MD2S4PK', { page_path: location.pathname + location.search, }); }, 1000); diff --git a/src/server/Html.tsx b/src/server/Html.tsx index b7198592..b20448e1 100644 --- a/src/server/Html.tsx +++ b/src/server/Html.tsx @@ -79,15 +79,15 @@ function Html({ > From b5600d4b119923cd06265b756c93dd3c69940ed7 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 30 Aug 2023 15:16:17 +0900 Subject: [PATCH 006/132] feat: redirect to v3 client host --- .env => .env.development | 4 +++- .env.production | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) rename .env => .env.development (61%) create mode 100644 .env.production diff --git a/.env b/.env.development similarity index 61% rename from .env rename to .env.development index 97223465..99329aff 100644 --- a/.env +++ b/.env.development @@ -4,5 +4,7 @@ REACT_APP_CLIENT_V3_HOST=http://localhost:3001 REACT_APP_API_HOST=http://localhost:5002/ -REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/ +REACT_APP_CLIENT_V3_HOST=http://localhost:3001/ + +REACT_APP_GRAPHQL_HOST=http://localhost:5002/ REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..a118abc2 --- /dev/null +++ b/.env.production @@ -0,0 +1,8 @@ +PUBLIC_URL=/ + +REACT_APP_API_HOST=http://localhost:5002/ + +REACT_APP_CLIENT_V3_HOST=http://localhost:3001/ + +REACT_APP_GRAPHQL_HOST=https://v2.velog.io/ +REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file From 71fd338ff4358317974f8d90fba71d9aab6a6bb1 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 30 Aug 2023 15:57:25 +0900 Subject: [PATCH 007/132] chore: remove if condition in main page --- src/pages/home/HomePage.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx index dae68c44..956ee2ba 100644 --- a/src/pages/home/HomePage.tsx +++ b/src/pages/home/HomePage.tsx @@ -12,9 +12,7 @@ import FloatingHeader from '../../components/base/FloatingHeader'; export type HomePageProps = {}; function HomePage(props: HomePageProps) { - if (process.env.NODE_ENV === 'production') { - window.location.href = process.env.REACT_APP_CLIENT_V3_HOST!; - } + window.location.href = process.env.REACT_APP_CLIENT_V3_HOST!; return (
From aa496a434cfda612dd749a4ecceadb30a7a957c2 Mon Sep 17 00:00:00 2001 From: winverse Date: Wed, 6 Sep 2023 01:05:43 +0900 Subject: [PATCH 008/132] chore: change css --- src/components/common/LabelInput.tsx | 2 +- src/components/register/RegisterForm.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/common/LabelInput.tsx b/src/components/common/LabelInput.tsx index 38541dce..606564a3 100644 --- a/src/components/common/LabelInput.tsx +++ b/src/components/common/LabelInput.tsx @@ -61,7 +61,7 @@ const LabelInputBlock = styled.div<{ focus: boolean }>` border-color: ${themedPalette.primary1}; `} input { - width: 1; + width: 100%; } svg { font-size: 1.5rem; diff --git a/src/components/register/RegisterForm.tsx b/src/components/register/RegisterForm.tsx index 9b3cdbaa..d780b7f5 100644 --- a/src/components/register/RegisterForm.tsx +++ b/src/components/register/RegisterForm.tsx @@ -78,7 +78,7 @@ const RegisterForm: React.FC = ({ label="아이디" placeholder="아이디를 입력하세요" value={form.username} - size={15} + size={20} /> Date: Fri, 8 Sep 2023 13:23:23 +0900 Subject: [PATCH 009/132] chore: clean up env --- .env.development | 3 --- .env.production | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.env.development b/.env.development index 99329aff..c370e8e7 100644 --- a/.env.development +++ b/.env.development @@ -1,10 +1,7 @@ PUBLIC_URL=/ REACT_APP_CLIENT_V3_HOST=http://localhost:3001 - REACT_APP_API_HOST=http://localhost:5002/ -REACT_APP_CLIENT_V3_HOST=http://localhost:3001/ - REACT_APP_GRAPHQL_HOST=http://localhost:5002/ REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file diff --git a/.env.production b/.env.production index a118abc2..51ff374c 100644 --- a/.env.production +++ b/.env.production @@ -1,8 +1,7 @@ PUBLIC_URL=/ +REACT_APP_CLIENT_V3_HOST=http://localhost:3001 REACT_APP_API_HOST=http://localhost:5002/ -REACT_APP_CLIENT_V3_HOST=http://localhost:3001/ - REACT_APP_GRAPHQL_HOST=https://v2.velog.io/ REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file From 766074eabc7cc072f7d2570f105c1b8287bea977 Mon Sep 17 00:00:00 2001 From: winverse Date: Wed, 13 Sep 2023 16:51:11 +0900 Subject: [PATCH 010/132] feat: Implement follow button in Post page --- .gitignore | 2 +- src/components/common/UserProfile.tsx | 42 ++++++++++++++++-------- src/components/post/MobileLikeButton.tsx | 9 ++++- src/components/post/PostFollowButton.tsx | 38 +++++++++++++++++++++ src/components/post/PostHead.tsx | 20 +++++------ 5 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 src/components/post/PostFollowButton.tsx diff --git a/.gitignore b/.gitignore index c70b7cf4..b91ca42f 100755 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,4 @@ jspm_packages # Serverless directories .serverless -.webpack \ No newline at end of file +.webpack diff --git a/src/components/common/UserProfile.tsx b/src/components/common/UserProfile.tsx index 22b5d00d..7d72f4a9 100644 --- a/src/components/common/UserProfile.tsx +++ b/src/components/common/UserProfile.tsx @@ -16,6 +16,7 @@ import SkeletonTexts from './SkeletonTexts'; import { Link } from 'react-router-dom'; import media from '../../lib/styles/media'; import optimizeImage from '../../lib/optimizeImage'; +import PostFollowButton from '../post/PostFollowButton'; const UserProfileBlock = styled.div` ${media.medium} { @@ -26,7 +27,17 @@ const UserProfileBlock = styled.div` const Section = styled.div` display: flex; - align-items: center; + justify-content: space-between; + .left { + display: flex; + align-items: center; + } + + .right { + display: flex; + align-items: center; + } + ${media.small} { flex-direction: column; align-items: flex-start; @@ -169,18 +180,23 @@ const UserProfile: React.FC = ({ return (
- - profile - - -
- {displayName} -
-
{description}
-
+
+ + profile + + +
+ {displayName} +
+
{description}
+
+
+
+ +
diff --git a/src/components/post/MobileLikeButton.tsx b/src/components/post/MobileLikeButton.tsx index da6f412c..3ebb8988 100644 --- a/src/components/post/MobileLikeButton.tsx +++ b/src/components/post/MobileLikeButton.tsx @@ -2,6 +2,7 @@ import React from 'react'; import styled, { css } from 'styled-components'; import { themedPalette } from '../../lib/styles/themes'; import { LikeIcon } from '../../static/svg'; +import media from '../../lib/styles/media'; export type MobileLikeButtonProps = { likes: number; @@ -19,11 +20,12 @@ function MobileLikeButton({ likes, onToggle, liked }: MobileLikeButtonProps) { } const Button = styled.button<{ liked: boolean }>` + display: none; + align-items: center; background: ${themedPalette.bg_element1}; border: 1px solid ${themedPalette.border2}; padding-left: 0.75rem; padding-right: 0.75rem; - display: flex; align-items: center; height: 1.5rem; border-radius: 0.75rem; @@ -49,6 +51,11 @@ const Button = styled.button<{ liked: boolean }>` color: white; } `} + + ${media.medium} { + display: flex; + margin-left: 0.5rem; + } `; export default MobileLikeButton; diff --git a/src/components/post/PostFollowButton.tsx b/src/components/post/PostFollowButton.tsx new file mode 100644 index 00000000..9cdb6f03 --- /dev/null +++ b/src/components/post/PostFollowButton.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import styled from 'styled-components'; +import media from '../../lib/styles/media'; +import { buttonColorMap } from '../../lib/styles/palette'; + +export interface PostFollowButtonProps {} + +const FollowButtonBlock = styled.button` + outline: none; + border: none; + font-size: 1rem; + cursor: pointer; + padding-left: 1rem; + padding-right: 1rem; + height: 2rem; + border-radius: 1rem; + background: ${buttonColorMap['teal'].background}; + color: ${buttonColorMap['teal'].color}; + font-weight: 600; + &:hover { + background: ${buttonColorMap['teal'].hoverBackground}; + } + + ${media.medium} { + font-size: 0.875rem; + border-radius: 0.75rem; + padding-left: 0.75rem; + padding-right: 0.75rem; + border-radius: 0.75rem; + height: 24px; + } +`; + +const PostFollowButton: React.FC = () => { + return 팔로우; +}; + +export default PostFollowButton; diff --git a/src/components/post/PostHead.tsx b/src/components/post/PostHead.tsx index 2728ba86..1c795881 100644 --- a/src/components/post/PostHead.tsx +++ b/src/components/post/PostHead.tsx @@ -12,6 +12,7 @@ import TagList from '../common/TagList'; import { Link } from 'react-router-dom'; import PrivatePostLabel from '../common/PrivatePostLabel'; import optimizeImage from '../../lib/optimizeImage'; +import PostFollowButton from './PostFollowButton'; const PostHeadBlock = styled(VelogResponsive)` margin-top: 5.5rem; @@ -44,12 +45,12 @@ const PostHeadBlock = styled(VelogResponsive)` `; const SubInfo = styled.div` - align-items: center; font-size: 1rem; color: ${themedPalette.text2}; /* font-family: 'Spoqa Han Sans'; */ display: flex; justify-content: space-between; + align-items: center; .information { .username { color: ${themedPalette.text1}; @@ -77,6 +78,10 @@ const SubInfo = styled.div` } `; +const SubInfoRight = styled.div` + display: flex; +`; + const EditRemoveGroup = styled.div` display: flex; justify-content: flex-end; @@ -119,14 +124,6 @@ const Thumbnail = styled.img` } `; -const MobileOnly = styled.div` - align-items: center; - display: none; - ${media.medium} { - display: flex; - } -`; - export interface PostHeadProps { title: string; tags: string[]; @@ -200,7 +197,10 @@ const PostHead: React.FC = ({ )} - {mobileLikeButton} + + {!ownPost && } + {mobileLikeButton} + {shareButtons} From 0d89c22ba557ebbfd9ca84949eb5d13a0d436455 Mon Sep 17 00:00:00 2001 From: winverse Date: Wed, 13 Sep 2023 20:10:01 +0900 Subject: [PATCH 011/132] styles: change postFollowButton css --- src/components/common/UserProfile.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/common/UserProfile.tsx b/src/components/common/UserProfile.tsx index 7d72f4a9..43a9abcd 100644 --- a/src/components/common/UserProfile.tsx +++ b/src/components/common/UserProfile.tsx @@ -28,20 +28,15 @@ const UserProfileBlock = styled.div` const Section = styled.div` display: flex; justify-content: space-between; + align-items: center; .left { display: flex; - align-items: center; - } - .right { - display: flex; - align-items: center; + ${media.small} { + flex-direction: column; + } } - ${media.small} { - flex-direction: column; - align-items: flex-start; - } img { display: block; width: 8rem; From 192bd574d944d7df8ae4fa516ad958a81743a5f3 Mon Sep 17 00:00:00 2001 From: winverse Date: Thu, 14 Sep 2023 16:02:13 +0900 Subject: [PATCH 012/132] feat: Add followed value when read post --- src/lib/graphql/post.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/graphql/post.ts b/src/lib/graphql/post.ts index 33190713..3e782cb3 100644 --- a/src/lib/graphql/post.ts +++ b/src/lib/graphql/post.ts @@ -319,6 +319,7 @@ export const READ_POST = gql` } } } + followed } } `; From 9bb8b66d261be302dc5718fbd391fc57dd124955 Mon Sep 17 00:00:00 2001 From: winverse Date: Thu, 14 Sep 2023 21:21:16 +0900 Subject: [PATCH 013/132] feat: connect to follow api --- src/components/common/UserProfile.tsx | 7 +-- src/components/post/PostFollowButton.tsx | 55 ++++++++++++---- src/components/post/PostHead.tsx | 5 +- src/containers/post/PostViewer.tsx | 62 +++++++++++++++++++ src/containers/velog/UserProfileContainer.tsx | 8 +-- src/lib/graphql/__data__/post.data.ts | 4 +- src/lib/graphql/post.ts | 1 + src/lib/graphql/user.ts | 12 ++++ 8 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/components/common/UserProfile.tsx b/src/components/common/UserProfile.tsx index 43a9abcd..fc040ca7 100644 --- a/src/components/common/UserProfile.tsx +++ b/src/components/common/UserProfile.tsx @@ -16,7 +16,6 @@ import SkeletonTexts from './SkeletonTexts'; import { Link } from 'react-router-dom'; import media from '../../lib/styles/media'; import optimizeImage from '../../lib/optimizeImage'; -import PostFollowButton from '../post/PostFollowButton'; const UserProfileBlock = styled.div` ${media.medium} { @@ -143,6 +142,7 @@ export interface UserProfileProps { description: string; profileLinks: ProfileLinks; username: string; + followButton?: React.ReactNode; } function includeProtocol(address: string) { @@ -157,6 +157,7 @@ const UserProfile: React.FC = ({ description, profileLinks, username, + followButton, }) => { const { email, facebook, github, twitter, url } = profileLinks; const [hoverEmail, setHoverEmail] = useState(false); @@ -189,9 +190,7 @@ const UserProfile: React.FC = ({
{description}
-
- -
+ {followButton &&
{followButton}
} diff --git a/src/components/post/PostFollowButton.tsx b/src/components/post/PostFollowButton.tsx index 9cdb6f03..4fbbae10 100644 --- a/src/components/post/PostFollowButton.tsx +++ b/src/components/post/PostFollowButton.tsx @@ -1,11 +1,29 @@ import * as React from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import media from '../../lib/styles/media'; import { buttonColorMap } from '../../lib/styles/palette'; -export interface PostFollowButtonProps {} +export interface PostFollowButtonProps { + followed: boolean; + onToggle: () => void; +} -const FollowButtonBlock = styled.button` +const PostFollowButton: React.FC = ({ + onToggle, + followed, +}) => { + return ( + + {followed ? '팔로잉' : '팔로우'} + + ); +}; + +const FollowButtonBlock = styled.button<{ followed: boolean }>` outline: none; border: none; font-size: 1rem; @@ -14,12 +32,28 @@ const FollowButtonBlock = styled.button` padding-right: 1rem; height: 2rem; border-radius: 1rem; - background: ${buttonColorMap['teal'].background}; - color: ${buttonColorMap['teal'].color}; + + ${(props) => + !props.followed && + css` + background: ${buttonColorMap['teal'].background}; + color: ${buttonColorMap['teal'].color}; + &:hover { + background: ${buttonColorMap['teal'].hoverBackground}; + } + `} + + ${(props) => + props.followed && + css` + background: ${buttonColorMap['lightGray'].background}; + color: ${buttonColorMap['lightGray'].color}; + &:hover { + background: ${buttonColorMap['lightGray'].hoverBackground}; + } + `} + font-weight: 600; - &:hover { - background: ${buttonColorMap['teal'].hoverBackground}; - } ${media.medium} { font-size: 0.875rem; @@ -30,9 +64,4 @@ const FollowButtonBlock = styled.button` height: 24px; } `; - -const PostFollowButton: React.FC = () => { - return 팔로우; -}; - export default PostFollowButton; diff --git a/src/components/post/PostHead.tsx b/src/components/post/PostHead.tsx index 1c795881..a3cc48cd 100644 --- a/src/components/post/PostHead.tsx +++ b/src/components/post/PostHead.tsx @@ -12,7 +12,6 @@ import TagList from '../common/TagList'; import { Link } from 'react-router-dom'; import PrivatePostLabel from '../common/PrivatePostLabel'; import optimizeImage from '../../lib/optimizeImage'; -import PostFollowButton from './PostFollowButton'; const PostHeadBlock = styled(VelogResponsive)` margin-top: 5.5rem; @@ -145,6 +144,7 @@ export interface PostHeadProps { toc: React.ReactNode; isPrivate?: boolean; mobileLikeButton: React.ReactNode; + followButton: React.ReactNode; onOpenStats(): void; } @@ -165,6 +165,7 @@ const PostHead: React.FC = ({ isPrivate, mobileLikeButton, onOpenStats, + followButton, }) => { const [askRemove, toggleAskRemove] = useToggle(false); @@ -198,7 +199,7 @@ const PostHead: React.FC = ({ )} - {!ownPost && } + {!ownPost && followButton} {mobileLikeButton} diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 760452dd..2159af59 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -37,6 +37,8 @@ import RelatedPost from './RelatedPost'; import optimizeImage from '../../lib/optimizeImage'; import { useSetShowFooter } from '../../components/velog/VelogPageTemplate'; import HorizontalBanner from './HorizontalBanner'; +import { FOLLOW_USER, UN_FOLLOW_USER } from '../../lib/graphql/user'; +import PostFollowButton from '../../components/post/PostFollowButton'; const UserProfileWrapper = styled(VelogResponsive)` margin-top: 16rem; @@ -96,6 +98,9 @@ const PostViewer: React.FC = ({ const [postView] = useMutation(POST_VIEW); const [likePost, { loading: loadingLike }] = useMutation(LIKE_POST); const [unlikePost, { loading: loadingUnlike }] = useMutation(UNLIKE_POST); + const [followUser, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); + const [unFollowUser, { loading: loadingUnFollowUser }] = + useMutation(UN_FOLLOW_USER); const { showNotFound } = useNotFound(); // const userLogo = useSelector((state: RootState) => state.header.userLogo); // const velogTitle = useMemo(() => { @@ -292,6 +297,51 @@ const PostViewer: React.FC = ({ } }; + const onFollowToggle = async () => { + if (loadingFollowUser || loadingUnFollowUser) return; + + const variables = { + follow_user_id: post.user.id, + }; + + const followFragment = gql` + fragment post on Post { + follwed + } + `; + + try { + if (!user) { + toast.error('로그인 후 이용해주세요.'); + return; + } + + if (post.followed) { + client.writeFragment({ + id: `Post:${post.id}`, + fragment: followFragment, + data: { + followed: false, + __typename: 'Post', + }, + }); + await unFollowUser({ variables }); + } else { + client.writeFragment({ + id: `Post:${post.id}`, + fragment: followFragment, + data: { + followed: true, + __typename: 'Post', + }, + }); + await followUser({ variables }); + } + } catch (e) { + console.log(e); + } + }; + const onShareClick = (type: 'facebook' | 'twitter' | 'clipboard') => { const { url } = match; const link = `https://velog.io${url}`; @@ -387,6 +437,12 @@ const PostViewer: React.FC = ({ onToggle={onLikeToggle} /> } + followButton={ + + } /> {userId === null && isVeryOld ? : null} @@ -397,6 +453,12 @@ const PostViewer: React.FC = ({ description={post.user.profile.short_bio} profileLinks={post.user.profile.profile_links} username={post.user.username} + followButton={ + + } /> diff --git a/src/containers/velog/UserProfileContainer.tsx b/src/containers/velog/UserProfileContainer.tsx index 4b9d5468..9f226ff3 100644 --- a/src/containers/velog/UserProfileContainer.tsx +++ b/src/containers/velog/UserProfileContainer.tsx @@ -32,12 +32,8 @@ const UserProfileContainer: React.FC = ({ if (loading || error || !data || !data.user) return ; - const { - display_name, - short_bio, - profile_links, - thumbnail, - } = data.user.profile; + const { display_name, short_bio, profile_links, thumbnail } = + data.user.profile; const isSeries = location.pathname.includes('/series'); diff --git a/src/lib/graphql/__data__/post.data.ts b/src/lib/graphql/__data__/post.data.ts index 602f73b5..cc0332d2 100644 --- a/src/lib/graphql/__data__/post.data.ts +++ b/src/lib/graphql/__data__/post.data.ts @@ -7,8 +7,7 @@ export const postData: { post: SinglePost } = { released_at: '2018-09-08T10:19:35.556Z', updated_at: '2019-07-30T14:19:14.326Z', tags: ['redux', '상태관리'], - body: - '리액트 생태계에서 사용되는 상태 관리 라이브러리는 대표적으로 Redux 와 MobX 가 있습니다. 이 둘의 특징을 배워보고 직접 사용하면서 알아가봅시다.\n\n## 상태 관리 라이브러리의 필요성\n\n상태 관리 라이브러리란게, 과연 필요할까요? 무조건 필요하지는 않습니다. 하지만 한가지는 확실합니다. 규모가 큰 앱에선 있는게, 확실히 편합니다. 제가 존경하는 개발자이면서도.. 리덕스의 라이브러리의 창시자인 Dan Abramov 는 말합니다. ["You might not need Redux"](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367) [(번역)](https://medium.com/@Dev_Bono/%EB%8B%B9%EC%8B%A0%EC%97%90%EA%B2%8C-redux%EB%8A%94-%ED%95%84%EC%9A%94-%EC%97%86%EC%9D%84%EC%A7%80%EB%8F%84-%EB%AA%A8%EB%A6%85%EB%8B%88%EB%8B%A4-b88dcd175754)\n\n실제로, 여러분은 리덕스 없이도 좋은 앱을 만들 수 있습니다. 상태 관리 라이브러리가 없으면, 이전에는 글로벌 상태 관리를 하기에 조금 번거로웠는데 리액트 16.3 에서 [Context API](https://react-context.vlpt.us/03.html) 가 더욱 좋아지면서 글로벌 상태 관리 또한 별도의 라이브러리 없이 할 수 있게 되었습니다.\n\n> 글로벌 상태 관리란, 컴포넌트 간의 데이터 교류, 특히 부모-자식 관계가 아닌 컴포넌트끼리 데이터 교류를 하는것을 의미합니다.\n\n하지만, 그럼에도 불구하고 저는 상태 관리 라이브러리를 결국에는 배워보는걸 권장합니다. 모르고 안 쓰는거랑, 알고 안 쓰는거랑 다르기 때문이죠.', + body: '리액트 생태계에서 사용되는 상태 관리 라이브러리는 대표적으로 Redux 와 MobX 가 있습니다. 이 둘의 특징을 배워보고 직접 사용하면서 알아가봅시다.\n\n## 상태 관리 라이브러리의 필요성\n\n상태 관리 라이브러리란게, 과연 필요할까요? 무조건 필요하지는 않습니다. 하지만 한가지는 확실합니다. 규모가 큰 앱에선 있는게, 확실히 편합니다. 제가 존경하는 개발자이면서도.. 리덕스의 라이브러리의 창시자인 Dan Abramov 는 말합니다. ["You might not need Redux"](https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367) [(번역)](https://medium.com/@Dev_Bono/%EB%8B%B9%EC%8B%A0%EC%97%90%EA%B2%8C-redux%EB%8A%94-%ED%95%84%EC%9A%94-%EC%97%86%EC%9D%84%EC%A7%80%EB%8F%84-%EB%AA%A8%EB%A6%85%EB%8B%88%EB%8B%A4-b88dcd175754)\n\n실제로, 여러분은 리덕스 없이도 좋은 앱을 만들 수 있습니다. 상태 관리 라이브러리가 없으면, 이전에는 글로벌 상태 관리를 하기에 조금 번거로웠는데 리액트 16.3 에서 [Context API](https://react-context.vlpt.us/03.html) 가 더욱 좋아지면서 글로벌 상태 관리 또한 별도의 라이브러리 없이 할 수 있게 되었습니다.\n\n> 글로벌 상태 관리란, 컴포넌트 간의 데이터 교류, 특히 부모-자식 관계가 아닌 컴포넌트끼리 데이터 교류를 하는것을 의미합니다.\n\n하지만, 그럼에도 불구하고 저는 상태 관리 라이브러리를 결국에는 배워보는걸 권장합니다. 모르고 안 쓰는거랑, 알고 안 쓰는거랑 다르기 때문이죠.', short_description: '리액트 생태계에서 사용되는 상태 관리 라이브러리는 대표적으로 Redux 와 MobX 가 있습니다. 이 둘의 특징을 배워보고 직접 사용하면서 알아가봅시다.\n\n상태 관리 라이브러리의 필요성\n\n상태 관리 라이브러리란게, 과연 필요할까요? 무조건 필요하지는 않습니다. 하지만 한가지는 확실합니다. 규모가 큰 앱에선 있는게, 확실히 편합니다. 제가 존경하는 개발자이면...', is_markdown: true, @@ -178,5 +177,6 @@ export const postData: { post: SinglePost } = { }, }, }, + followed: false, }, }; diff --git a/src/lib/graphql/post.ts b/src/lib/graphql/post.ts index 3e782cb3..d6d0b2a9 100644 --- a/src/lib/graphql/post.ts +++ b/src/lib/graphql/post.ts @@ -124,6 +124,7 @@ export interface SinglePost { liked: boolean; likes: number; linked_posts: LinkedPosts; + followed: boolean; } export interface CommentWithReplies { diff --git a/src/lib/graphql/user.ts b/src/lib/graphql/user.ts index f1fc9bc1..7d501f52 100644 --- a/src/lib/graphql/user.ts +++ b/src/lib/graphql/user.ts @@ -182,6 +182,18 @@ export const CONFIRM_CHANGE_EMAIL = gql` } `; +export const FOLLOW_USER = gql` + mutation Follow($follow_user_id: ID!) { + follow(follow_user_id: $follow_user_id) + } +`; + +export const UN_FOLLOW_USER = gql` + mutation UnFollow($follow_user_id: ID!) { + unFollow(follow_user_id: $follow_user_id) + } +`; + export type AcceptIntegrationResponse = { acceptIntegration: string; }; From 6271e1d3a38e92512c8069f9e70b2e1666a8a879 Mon Sep 17 00:00:00 2001 From: carrick Date: Thu, 14 Sep 2023 21:40:27 +0900 Subject: [PATCH 014/132] feat: Add follow feature to post view component --- src/containers/post/PostViewer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 2159af59..dc5e669e 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -306,7 +306,7 @@ const PostViewer: React.FC = ({ const followFragment = gql` fragment post on Post { - follwed + followed } `; From 834e79acb932a28f3a41c1151b430c491f9de80f Mon Sep 17 00:00:00 2001 From: carrick Date: Mon, 25 Sep 2023 18:46:41 +0900 Subject: [PATCH 015/132] fix: change email bug fix --- src/containers/etc/EmailChange.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/etc/EmailChange.tsx b/src/containers/etc/EmailChange.tsx index 0a763edc..52aa435f 100644 --- a/src/containers/etc/EmailChange.tsx +++ b/src/containers/etc/EmailChange.tsx @@ -39,7 +39,7 @@ const EmailChange: React.FC = ({ location, history }) => { await client.mutate({ mutation: CONFIRM_CHANGE_EMAIL, variables: { - code: query.code, + code: query.code.split(':')[1], }, }); From 24ac52ca08b7629b38c925e814cb218d759ed9f7 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 27 Sep 2023 15:11:59 +0900 Subject: [PATCH 016/132] refactor: change email --- src/containers/etc/EmailChange.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/etc/EmailChange.tsx b/src/containers/etc/EmailChange.tsx index 52aa435f..0a763edc 100644 --- a/src/containers/etc/EmailChange.tsx +++ b/src/containers/etc/EmailChange.tsx @@ -39,7 +39,7 @@ const EmailChange: React.FC = ({ location, history }) => { await client.mutate({ mutation: CONFIRM_CHANGE_EMAIL, variables: { - code: query.code.split(':')[1], + code: query.code, }, }); From 26ad9ef9f1063d85930929c5ec316a5c2eadc107 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 27 Sep 2023 19:11:35 +0900 Subject: [PATCH 017/132] fix: naming convention --- src/containers/post/PostViewer.tsx | 10 +++++----- src/lib/graphql/user.ts | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index dc5e669e..93f0b564 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -37,7 +37,7 @@ import RelatedPost from './RelatedPost'; import optimizeImage from '../../lib/optimizeImage'; import { useSetShowFooter } from '../../components/velog/VelogPageTemplate'; import HorizontalBanner from './HorizontalBanner'; -import { FOLLOW_USER, UN_FOLLOW_USER } from '../../lib/graphql/user'; +import { FOLLOW_USER, UNFOLLOW_USER } from '../../lib/graphql/user'; import PostFollowButton from '../../components/post/PostFollowButton'; const UserProfileWrapper = styled(VelogResponsive)` @@ -99,8 +99,8 @@ const PostViewer: React.FC = ({ const [likePost, { loading: loadingLike }] = useMutation(LIKE_POST); const [unlikePost, { loading: loadingUnlike }] = useMutation(UNLIKE_POST); const [followUser, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); - const [unFollowUser, { loading: loadingUnFollowUser }] = - useMutation(UN_FOLLOW_USER); + const [unfollowUser, { loading: loadingUnfollowUser }] = + useMutation(UNFOLLOW_USER); const { showNotFound } = useNotFound(); // const userLogo = useSelector((state: RootState) => state.header.userLogo); // const velogTitle = useMemo(() => { @@ -298,7 +298,7 @@ const PostViewer: React.FC = ({ }; const onFollowToggle = async () => { - if (loadingFollowUser || loadingUnFollowUser) return; + if (loadingFollowUser || loadingUnfollowUser) return; const variables = { follow_user_id: post.user.id, @@ -325,7 +325,7 @@ const PostViewer: React.FC = ({ __typename: 'Post', }, }); - await unFollowUser({ variables }); + await unfollowUser({ variables }); } else { client.writeFragment({ id: `Post:${post.id}`, diff --git a/src/lib/graphql/user.ts b/src/lib/graphql/user.ts index 7d501f52..1aec1096 100644 --- a/src/lib/graphql/user.ts +++ b/src/lib/graphql/user.ts @@ -188,9 +188,9 @@ export const FOLLOW_USER = gql` } `; -export const UN_FOLLOW_USER = gql` - mutation UnFollow($follow_user_id: ID!) { - unFollow(follow_user_id: $follow_user_id) +export const UNFOLLOW_USER = gql` + mutation Unfollow($follow_user_id: ID!) { + unfollow(follow_user_id: $follow_user_id) } `; From 6f81cc15d205c3c47257422b6bc8d7c1b7bba58b Mon Sep 17 00:00:00 2001 From: velopert Date: Sun, 1 Oct 2023 23:38:30 +0900 Subject: [PATCH 018/132] feat: change banner logic --- src/components/velog/VelogResponsive.tsx | 3 ++ src/containers/post/HorizontalBanner.tsx | 7 ++++- src/containers/post/PostViewer.tsx | 40 +++++++++++++++++++----- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/components/velog/VelogResponsive.tsx b/src/components/velog/VelogResponsive.tsx index 896c69b9..f774267f 100644 --- a/src/components/velog/VelogResponsive.tsx +++ b/src/components/velog/VelogResponsive.tsx @@ -14,18 +14,21 @@ const VelogResponsiveBlock = styled.div` export interface VelogResponsiveProps { className?: string; style?: React.CSSProperties; + onClick?: () => void; } const VelogResponsive: React.FC = ({ children, className, style, + onClick, }) => { return ( ); }; diff --git a/src/containers/post/HorizontalBanner.tsx b/src/containers/post/HorizontalBanner.tsx index 9045cc52..9aa6259b 100644 --- a/src/containers/post/HorizontalBanner.tsx +++ b/src/containers/post/HorizontalBanner.tsx @@ -1,14 +1,19 @@ import React, { useEffect } from 'react'; import styled from 'styled-components'; import VelogResponsive from '../../components/velog/VelogResponsive'; +import gtag from '../../lib/gtag'; function HorizontalBanner() { useEffect(() => { (window.adsbygoogle = window.adsbygoogle || []).push({}); }, []); + const onClick = () => { + gtag('event', 'banner_click'); + }; + return ( - + = ({ }; }, [onScroll]); + const shouldShowBanner = useMemo(() => { + if (!data?.post) return; + + const post = data.post; + const isOwnPost = post.user.id === userId; + const isVeryOld = + Date.now() - new Date(post.released_at).getTime() > + 1000 * 60 * 60 * 24 * 30; + + if (isOwnPost) return false; + if (!isVeryOld) return false; + return true; + }, [data?.post]); + + useEffect(() => { + if (!data?.post?.id) return; + if (!shouldShowBanner) return; + gtag('event', 'banner_view'); + console.log('banner_view'); + }, [data?.post?.id, shouldShowBanner]); + const onRemove = async () => { if (!data || !data.post) return; try { @@ -320,9 +348,7 @@ const PostViewer: React.FC = ({ const { post } = data; - const isVeryOld = - Date.now() - new Date(post.released_at).getTime() > - 1000 * 60 * 60 * 24 * 180; + const isContentLongEnough = post.body.length > 500; const url = `https://velog.io/@${username}/${post.url_slug}`; @@ -388,7 +414,7 @@ const PostViewer: React.FC = ({ /> } /> - {userId === null && isVeryOld ? : null} + {shouldShowBanner ? : null} = ({ } /> )} */} - {userId === null && isVeryOld && post.body.length > 300 ? ( - - ) : null} + {shouldShowBanner && isContentLongEnough ? : null} Date: Thu, 5 Oct 2023 01:40:11 +0900 Subject: [PATCH 019/132] feat: hide follow button by post owner --- src/components/common/UserProfile.tsx | 6 +++++- src/containers/post/PostViewer.tsx | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/common/UserProfile.tsx b/src/components/common/UserProfile.tsx index fc040ca7..aa4068bf 100644 --- a/src/components/common/UserProfile.tsx +++ b/src/components/common/UserProfile.tsx @@ -143,6 +143,7 @@ export interface UserProfileProps { profileLinks: ProfileLinks; username: string; followButton?: React.ReactNode; + ownPost?: boolean; } function includeProtocol(address: string) { @@ -158,6 +159,7 @@ const UserProfile: React.FC = ({ profileLinks, username, followButton, + ownPost = false, }) => { const { email, facebook, github, twitter, url } = profileLinks; const [hoverEmail, setHoverEmail] = useState(false); @@ -190,7 +192,9 @@ const UserProfile: React.FC = ({
{description}
- {followButton &&
{followButton}
} + {!ownPost && followButton && ( +
{followButton}
+ )} diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 93f0b564..754a9ec5 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -453,6 +453,7 @@ const PostViewer: React.FC = ({ description={post.user.profile.short_bio} profileLinks={post.user.profile.profile_links} username={post.user.username} + ownPost={post.user.id === userId} followButton={ Date: Fri, 6 Oct 2023 20:24:45 +0900 Subject: [PATCH 020/132] fix: RelatedPost props --- src/containers/post/PostViewer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 6b7e5c08..651bdc50 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -457,7 +457,9 @@ const PostViewer: React.FC = ({ } /> )} */} - {showRecommends ? : null} + {showRecommends ? ( + + ) : null} ); }; From 10029e831b1ec06bc9ddb8fca88f3f0e96455751 Mon Sep 17 00:00:00 2001 From: velopert Date: Fri, 6 Oct 2023 21:13:11 +0900 Subject: [PATCH 021/132] fix: ad-code --- src/components/common/AdFeed.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/common/AdFeed.tsx b/src/components/common/AdFeed.tsx index 7e40b56b..18259136 100644 --- a/src/components/common/AdFeed.tsx +++ b/src/components/common/AdFeed.tsx @@ -64,9 +64,9 @@ function AdFeed({ forPost, index }: { forPost?: boolean; index: number }) { className="adsbygoogle" style={{ display: 'block' }} data-ad-format="fluid" - data-ad-layout-key="-6u+e5+1a-3q+77" - data-ad-client="ca-pub-5574866530496701" - data-ad-slot="2841722540" + data-ad-layout-key="-6c+ce+2v-x+66" + data-ad-client="ca-pub-9161852896103498" + data-ad-slot="9446928451" >
); @@ -87,18 +87,18 @@ function AdFeed({ forPost, index }: { forPost?: boolean; index: number }) { className="adsbygoogle" style={{ display: 'block' }} data-ad-format="fluid" - data-ad-layout-key="-6u+e5+1a-3q+77" - data-ad-client="ca-pub-5574866530496701" - data-ad-slot="8480422066" + data-ad-layout-key="-6c+ce+2v-x+66" + data-ad-client="ca-pub-9161852896103498" + data-ad-slot="2793890198" > ) : ( )} {/* {isMobile ? ( From 66745f0423a7d5875535d719164c410ec8803ecc Mon Sep 17 00:00:00 2001 From: velopert Date: Sun, 8 Oct 2023 19:51:41 +0900 Subject: [PATCH 022/132] fix: ad logic --- src/containers/post/HorizontalBanner.tsx | 33 ++++++++++++++------ src/containers/post/PostViewer.tsx | 39 ++++++++---------------- src/containers/post/RelatedPost.tsx | 13 ++------ 3 files changed, 40 insertions(+), 45 deletions(-) diff --git a/src/containers/post/HorizontalBanner.tsx b/src/containers/post/HorizontalBanner.tsx index 9aa6259b..621e43a1 100644 --- a/src/containers/post/HorizontalBanner.tsx +++ b/src/containers/post/HorizontalBanner.tsx @@ -3,7 +3,11 @@ import styled from 'styled-components'; import VelogResponsive from '../../components/velog/VelogResponsive'; import gtag from '../../lib/gtag'; -function HorizontalBanner() { +type Props = { + isDisplayAd?: boolean; +}; + +function HorizontalBanner({ isDisplayAd = false }: Props) { useEffect(() => { (window.adsbygoogle = window.adsbygoogle || []).push({}); }, []); @@ -14,14 +18,25 @@ function HorizontalBanner() { return ( - + {isDisplayAd ? ( + + ) : ( + + )} ); } diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 651bdc50..5b00a36d 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -208,14 +208,24 @@ const PostViewer: React.FC = ({ if (isOwnPost) return false; if (!isVeryOld) return false; return true; - }, [data?.post]); + }, [data?.post, userId]); + + const shouldShowFooterBanner = useMemo(() => { + if (shouldShowBanner) return false; + if (!data?.post) return false; + if (userId) return false; + return true; + }, [userId, data?.post]); useEffect(() => { if (!data?.post?.id) return; if (!shouldShowBanner) return; gtag('event', 'banner_view'); console.log('banner_view'); - }, [data?.post?.id, shouldShowBanner]); + if (userId) { + gtag('event', 'banner_view_user'); + } + }, [data?.post?.id, shouldShowBanner, userId]); const onRemove = async () => { if (!data || !data.post) return; @@ -426,37 +436,14 @@ const PostViewer: React.FC = ({ /> - {/* {showRecommends && userId === null && !isVeryOld && ( - - // 1000 * 60 * 60 * 24 * 21 - } - /> - )} */} {shouldShowBanner && isContentLongEnough ? : null} - + {shouldShowFooterBanner ? : null} - {/* {showRecommends && (userId !== null || isVeryOld) && ( - - // 1000 * 60 * 60 * 24 * 30 - } - /> - )} */} {showRecommends ? ( ) : null} diff --git a/src/containers/post/RelatedPost.tsx b/src/containers/post/RelatedPost.tsx index 07e5a98b..84911829 100644 --- a/src/containers/post/RelatedPost.tsx +++ b/src/containers/post/RelatedPost.tsx @@ -39,19 +39,12 @@ function RelatedPost({ const cloned: (PartialPost | undefined)[] = [ ...data.post.recommended_posts, ]; - // get random number between 0 and length of array - const randomIndex = () => Math.floor(Math.random() * 8); + // get random number between 0 and 3 + const randomIndex = () => Math.floor(Math.random() * 3); const firstAdIndex = randomIndex(); - const secondAdIndex = (() => { - let index = randomIndex(); - while (index === firstAdIndex) { - index = randomIndex(); - } - return index; - })(); cloned[firstAdIndex] = undefined; - cloned[secondAdIndex] = undefined; + return cloned; }, [data, showAds, adBlocked]); From 37ceae3157acc0d70e1e62a2dcf8c9e8b00d67a2 Mon Sep 17 00:00:00 2001 From: velopert Date: Thu, 12 Oct 2023 01:35:43 +0900 Subject: [PATCH 023/132] fix: do not stringify if it is already string --- src/lib/storage.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/storage.ts b/src/lib/storage.ts index af20e37f..474b9e9a 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -16,7 +16,7 @@ class FallbackStorage { valid: boolean = checkLocalStorage(); setItem(key: string, value: any) { - const string = JSON.stringify(value); + const string = typeof value === 'string' ? value : JSON.stringify(value); if (this.valid) { localStorage.setItem(key, string); return; @@ -28,11 +28,12 @@ class FallbackStorage { let value = this.valid ? localStorage.getItem(key) : this.fallbackStorage[key]; + if (!value) return null; try { const parsed = JSON.parse(value || ''); return parsed; } catch (e) { - return null; + return value || null; } } From 74a1f238e51cdf6d945bb91f9724c802820190ce Mon Sep 17 00:00:00 2001 From: velopert Date: Thu, 12 Oct 2023 02:49:42 +0900 Subject: [PATCH 024/132] fix: refresh when moving to home --- src/components/base/HeaderLogo.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/base/HeaderLogo.tsx b/src/components/base/HeaderLogo.tsx index b05e265b..c097b88c 100644 --- a/src/components/base/HeaderLogo.tsx +++ b/src/components/base/HeaderLogo.tsx @@ -22,9 +22,9 @@ const HeaderLogo: React.FC = ({ if (!custom) { return ( - + - + ); } @@ -33,7 +33,7 @@ const HeaderLogo: React.FC = ({ const velogPath = `/@${username}`; return ( - + @@ -74,7 +74,7 @@ const HeaderLogoBlock = styled.div` } `; -const VelogLogoLink = styled(Link)` +const VelogLogoLink = styled.a` color: inherit; svg { From 7b4aa14b352d100df10f403a3414d65529bc6c40 Mon Sep 17 00:00:00 2001 From: velopert Date: Thu, 12 Oct 2023 03:24:03 +0900 Subject: [PATCH 025/132] fix: redirect new home onlogin --- src/containers/etc/EmailLogin.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/etc/EmailLogin.tsx b/src/containers/etc/EmailLogin.tsx index 5062b238..d32bc981 100644 --- a/src/containers/etc/EmailLogin.tsx +++ b/src/containers/etc/EmailLogin.tsx @@ -42,7 +42,7 @@ const EmailLogin: React.FC = ({ location, history }) => { }); storage.setItem('CURRENT_USER', response.data.auth); - history.replace('/'); + window.location.href = '/'; } catch (e) { // TODO: show 401 toast.error('잘못된 접근입니다.'); From 954b376e7a6ca282b98e1ae13d8c1427427a481b Mon Sep 17 00:00:00 2001 From: carrick Date: Mon, 23 Oct 2023 12:40:37 +0900 Subject: [PATCH 026/132] chore: handle env --- .env.production | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.production b/.env.production index 51ff374c..034cf768 100644 --- a/.env.production +++ b/.env.production @@ -3,5 +3,5 @@ PUBLIC_URL=/ REACT_APP_CLIENT_V3_HOST=http://localhost:3001 REACT_APP_API_HOST=http://localhost:5002/ -REACT_APP_GRAPHQL_HOST=https://v2.velog.io/ +REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/ REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file From e402a0f0e55c5c05d6d0238caf807d8d4672813b Mon Sep 17 00:00:00 2001 From: carrick Date: Sun, 29 Oct 2023 23:13:29 +0900 Subject: [PATCH 027/132] refactor: follow --- src/containers/post/PostViewer.tsx | 10 +++++----- src/lib/graphql/post.ts | 2 +- src/lib/graphql/user.ts | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 754a9ec5..9cc49ddb 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -98,8 +98,8 @@ const PostViewer: React.FC = ({ const [postView] = useMutation(POST_VIEW); const [likePost, { loading: loadingLike }] = useMutation(LIKE_POST); const [unlikePost, { loading: loadingUnlike }] = useMutation(UNLIKE_POST); - const [followUser, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); - const [unfollowUser, { loading: loadingUnfollowUser }] = + const [follow, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); + const [unfollow, { loading: loadingUnfollowUser }] = useMutation(UNFOLLOW_USER); const { showNotFound } = useNotFound(); // const userLogo = useSelector((state: RootState) => state.header.userLogo); @@ -301,7 +301,7 @@ const PostViewer: React.FC = ({ if (loadingFollowUser || loadingUnfollowUser) return; const variables = { - follow_user_id: post.user.id, + following_user_id: post.user.id, }; const followFragment = gql` @@ -325,7 +325,7 @@ const PostViewer: React.FC = ({ __typename: 'Post', }, }); - await unfollowUser({ variables }); + await unfollow({ variables }); } else { client.writeFragment({ id: `Post:${post.id}`, @@ -335,7 +335,7 @@ const PostViewer: React.FC = ({ __typename: 'Post', }, }); - await followUser({ variables }); + await follow({ variables }); } } catch (e) { console.log(e); diff --git a/src/lib/graphql/post.ts b/src/lib/graphql/post.ts index d6d0b2a9..8704a0d5 100644 --- a/src/lib/graphql/post.ts +++ b/src/lib/graphql/post.ts @@ -252,6 +252,7 @@ export const READ_POST = gql` url_slug likes liked + followed user { id username @@ -320,7 +321,6 @@ export const READ_POST = gql` } } } - followed } } `; diff --git a/src/lib/graphql/user.ts b/src/lib/graphql/user.ts index 1aec1096..12e402da 100644 --- a/src/lib/graphql/user.ts +++ b/src/lib/graphql/user.ts @@ -183,14 +183,14 @@ export const CONFIRM_CHANGE_EMAIL = gql` `; export const FOLLOW_USER = gql` - mutation Follow($follow_user_id: ID!) { - follow(follow_user_id: $follow_user_id) + mutation Follow($following_user_id: ID!) { + follow(following_user_id: $following_user_id) } `; export const UNFOLLOW_USER = gql` - mutation Unfollow($follow_user_id: ID!) { - unfollow(follow_user_id: $follow_user_id) + mutation Unfollow($following_user_id: ID!) { + unfollow(following_user_id: $following_user_id) } `; From 65e739e7a603932bae3a706ae54d9b5c137e2bba Mon Sep 17 00:00:00 2001 From: carrick Date: Mon, 30 Oct 2023 10:31:49 +0900 Subject: [PATCH 028/132] chore: change logo href --- src/components/base/HeaderLogo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/base/HeaderLogo.tsx b/src/components/base/HeaderLogo.tsx index def4ff63..4d365fd3 100644 --- a/src/components/base/HeaderLogo.tsx +++ b/src/components/base/HeaderLogo.tsx @@ -34,7 +34,7 @@ const HeaderLogo: React.FC = ({ const velogPath = `/@${username}`; return ( - + From 2e468267f98101b9c947779f520f70ee303e2989 Mon Sep 17 00:00:00 2001 From: carrick Date: Mon, 30 Oct 2023 10:43:22 +0900 Subject: [PATCH 029/132] fix: resolve eslint error --- src/containers/post/PostViewer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index eb981566..1380d0cc 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -213,14 +213,14 @@ const PostViewer: React.FC = ({ if (isOwnPost) return false; if (!isVeryOld) return false; return true; - }, [data?.post]); + }, [data, userId]); useEffect(() => { if (!data?.post?.id) return; if (!shouldShowBanner) return; gtag('event', 'banner_view'); console.log('banner_view'); - }, [data?.post?.id, shouldShowBanner]); + }, [data, shouldShowBanner]); const onRemove = async () => { if (!data || !data.post) return; From 96e5cde3527e5f02a2bcf174872a6df65dc694a1 Mon Sep 17 00:00:00 2001 From: carrick Date: Fri, 10 Nov 2023 06:16:00 +0900 Subject: [PATCH 030/132] fix: follow button style --- src/components/post/PostFollowButton.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/post/PostFollowButton.tsx b/src/components/post/PostFollowButton.tsx index 4fbbae10..51eaea85 100644 --- a/src/components/post/PostFollowButton.tsx +++ b/src/components/post/PostFollowButton.tsx @@ -32,6 +32,7 @@ const FollowButtonBlock = styled.button<{ followed: boolean }>` padding-right: 1rem; height: 2rem; border-radius: 1rem; + word-break: keep-all; ${(props) => !props.followed && From 7198295ce16a1b8fa47ffe32f3f2adf3814ae887 Mon Sep 17 00:00:00 2001 From: carrick Date: Fri, 10 Nov 2023 07:02:20 +0900 Subject: [PATCH 031/132] feat: apply VLink to Header --- src/components/base/HeaderUserMenu.tsx | 2 +- src/components/base/HeaderUserMenuItem.tsx | 34 +++++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/components/base/HeaderUserMenu.tsx b/src/components/base/HeaderUserMenu.tsx index 09c1138f..0dc6b88c 100644 --- a/src/components/base/HeaderUserMenu.tsx +++ b/src/components/base/HeaderUserMenu.tsx @@ -44,7 +44,7 @@ const HeaderUserMenu: React.FC = ({
- + 내 벨로그
diff --git a/src/components/base/HeaderUserMenuItem.tsx b/src/components/base/HeaderUserMenuItem.tsx index 5c0412f0..87ffd09c 100644 --- a/src/components/base/HeaderUserMenuItem.tsx +++ b/src/components/base/HeaderUserMenuItem.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled from 'styled-components'; import { Link } from 'react-router-dom'; import { themedPalette } from '../../lib/styles/themes'; +import VLink from '../common/VLink'; const WrapperLink = styled(Link)` display: block; @@ -9,6 +10,12 @@ const WrapperLink = styled(Link)` text-decoration: none; `; +const WrapperVLink = styled(VLink)` + display: block; + color: inherit; + text-decoration: none; +`; + const HeaderUserMenuItemBlock = styled.div` color: ${themedPalette.text1}; padding: 0.75rem 1rem; @@ -24,25 +31,38 @@ const HeaderUserMenuItemBlock = styled.div` interface HeaderUserMenuItemProps { to?: string; onClick?: () => void; + isMigrated?: boolean; } const HeaderUserMenuItem: React.FC = ({ children, to, onClick, + isMigrated = false, }) => { const jsx = ( {children} ); - return to ? ( - - {jsx} - - ) : ( - jsx - ); + + if (to && !isMigrated) { + return ( + + {jsx} + + ); + } + + if (to && isMigrated) { + return ( + + {jsx} + + ); + } + + return jsx; }; export default HeaderUserMenuItem; From 53179993b7a8696ce1b29a519edbe52c806e3031 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 29 Nov 2023 00:40:51 +0900 Subject: [PATCH 032/132] feat: implement follow button in userProfile component --- src/components/post/PostFollowButton.tsx | 219 ++++++++++++++++++----- src/containers/post/PostViewer.tsx | 58 +----- src/lib/graphql/__data__/post.data.ts | 2 +- src/lib/graphql/post.ts | 4 +- src/lib/graphql/user.ts | 1 + src/pages/velog/UserPage.tsx | 3 +- 6 files changed, 186 insertions(+), 101 deletions(-) diff --git a/src/components/post/PostFollowButton.tsx b/src/components/post/PostFollowButton.tsx index 51eaea85..ef29181e 100644 --- a/src/components/post/PostFollowButton.tsx +++ b/src/components/post/PostFollowButton.tsx @@ -1,68 +1,199 @@ import * as React from 'react'; import styled, { css } from 'styled-components'; import media from '../../lib/styles/media'; -import { buttonColorMap } from '../../lib/styles/palette'; +import { debounce } from 'throttle-debounce'; +import { useApolloClient, useMutation } from '@apollo/react-hooks'; +import { FOLLOW_USER, UNFOLLOW_USER } from '../../lib/graphql/user'; +import { gql } from 'apollo-boost'; +import useUser from '../../lib/hooks/useUser'; +import { toast } from 'react-toastify'; +import { themedPalette } from '../../lib/styles/themes'; export interface PostFollowButtonProps { + followingUserId: string; followed: boolean; - onToggle: () => void; } const PostFollowButton: React.FC = ({ - onToggle, + followingUserId, followed, }) => { + const client = useApolloClient(); + const currentUser = useUser(); + const [follow, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); + const [unfollow, { loading: loadingUnfollowUser }] = + useMutation(UNFOLLOW_USER); + + const [initialFollowState, setInitialFollowState] = + React.useState(followed); + const [currentFollowState, setCurrentFollowState] = + React.useState(followed); + + const [buttonText, setButtonText] = React.useState('팔로잉'); + + const onFollowButtonMouseLeave = () => { + setInitialFollowState(currentFollowState || false); + }; + + const onUnfollowButtonMouseEnter = () => { + setButtonText('언팔로우'); + }; + + const onUnfollowButtonMouseLeave = () => { + setButtonText('팔로잉'); + }; + + const onClick = debounce(300, async () => { + if (loadingFollowUser || loadingUnfollowUser) return; + + const variables = { + following_user_id: followingUserId, + }; + + const followFragment = gql` + fragment user on User { + is_followed + } + `; + + try { + if (!currentUser) { + toast.error('로그인 후 이용해주세요.'); + return; + } + + if (currentFollowState) { + client.writeFragment({ + id: `User:${followingUserId}`, + fragment: followFragment, + data: { + is_followed: false, + __typename: 'User', + }, + }); + await unfollow({ variables }); + } else { + client.writeFragment({ + id: `User:${followingUserId}`, + fragment: followFragment, + data: { + is_followed: true, + __typename: 'User', + }, + }); + await follow({ variables }); + setButtonText('팔로잉'); + } + + setInitialFollowState(!currentFollowState); + setCurrentFollowState(!currentFollowState); + } catch (error) { + console.log('handle follow state error', error); + } + }); + + React.useEffect(() => { + setInitialFollowState(followed); + setCurrentFollowState(followed); + }, [followed]); + return ( - {followed ? '팔로잉' : '팔로우'} + {!initialFollowState ? ( + + ) : ( + + )} ); }; -const FollowButtonBlock = styled.button<{ followed: boolean }>` - outline: none; - border: none; - font-size: 1rem; - cursor: pointer; - padding-left: 1rem; - padding-right: 1rem; - height: 2rem; - border-radius: 1rem; - word-break: keep-all; - - ${(props) => - !props.followed && - css` - background: ${buttonColorMap['teal'].background}; - color: ${buttonColorMap['teal'].color}; - &:hover { - background: ${buttonColorMap['teal'].hoverBackground}; - } - `} - - ${(props) => - props.followed && - css` - background: ${buttonColorMap['lightGray'].background}; - color: ${buttonColorMap['lightGray'].color}; - &:hover { - background: ${buttonColorMap['lightGray'].hoverBackground}; - } - `} - - font-weight: 600; +const FollowButtonBlock = styled.div<{ + followed: boolean; + unfollowed: boolean; +}>` + width: 96px; + height: 32px; + font-size: 16px; - ${media.medium} { - font-size: 0.875rem; - border-radius: 0.75rem; - padding-left: 0.75rem; - padding-right: 0.75rem; - border-radius: 0.75rem; + ${media.small} { + width: 80px; height: 24px; + font-size: 14px; + } + + ${media.custom(425)} { + width: 72px; + font-size: 12px; + } + + .button { + display: flex; + box-shadow: none; + align-items: center; + justify-content: center; + background-color: white; + cursor: pointer; + border-radius: 16px; + font-weight: 700; + width: 100%; + height: 100%; + white-space: nowrap; + outline: none; + font-size: 16px; + + ${media.small} { + font-size: 14px; + } + + ${media.custom(425)} { + font-size: 12px; + } + } + + .follow-button { + color: ${themedPalette.primary1}; + border: 1px solid ${themedPalette.primary1}; + + ${(props) => + props.followed && + css` + color: ${themedPalette.bg_element6}; + border: 1px solid ${themedPalette.bg_element6}; + `} + } + + .unfollow-button { + color: ${themedPalette.bg_element6}; + border: 1px solid ${themedPalette.bg_element6}; + + ${(props) => + props.unfollowed && + css` + &:hover, + &:active { + color: ${themedPalette.destructive1}; + border: 1px solid ${themedPalette.destructive1}; + } + `} } `; + export default PostFollowButton; diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 1380d0cc..2c400ef2 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -44,7 +44,6 @@ import optimizeImage from '../../lib/optimizeImage'; import { useSetShowFooter } from '../../components/velog/VelogPageTemplate'; import HorizontalBanner from './HorizontalBanner'; import gtag from '../../lib/gtag'; -import { FOLLOW_USER, UNFOLLOW_USER } from '../../lib/graphql/user'; import PostFollowButton from '../../components/post/PostFollowButton'; const UserProfileWrapper = styled(VelogResponsive)` @@ -105,10 +104,8 @@ const PostViewer: React.FC = ({ const [postView] = useMutation(POST_VIEW); const [likePost, { loading: loadingLike }] = useMutation(LIKE_POST); const [unlikePost, { loading: loadingUnlike }] = useMutation(UNLIKE_POST); - const [follow, { loading: loadingFollowUser }] = useMutation(FOLLOW_USER); - const [unfollow, { loading: loadingUnfollowUser }] = - useMutation(UNFOLLOW_USER); const { showNotFound } = useNotFound(); + // const userLogo = useSelector((state: RootState) => state.header.userLogo); // const velogTitle = useMemo(() => { // if (!userLogo || !userLogo.title) return `${username}.log`; @@ -325,51 +322,6 @@ const PostViewer: React.FC = ({ } }; - const onFollowToggle = async () => { - if (loadingFollowUser || loadingUnfollowUser) return; - - const variables = { - following_user_id: post.user.id, - }; - - const followFragment = gql` - fragment post on Post { - followed - } - `; - - try { - if (!user) { - toast.error('로그인 후 이용해주세요.'); - return; - } - - if (post.followed) { - client.writeFragment({ - id: `Post:${post.id}`, - fragment: followFragment, - data: { - followed: false, - __typename: 'Post', - }, - }); - await unfollow({ variables }); - } else { - client.writeFragment({ - id: `Post:${post.id}`, - fragment: followFragment, - data: { - followed: true, - __typename: 'Post', - }, - }); - await follow({ variables }); - } - } catch (e) { - console.log(e); - } - }; - const onShareClick = (type: 'facebook' | 'twitter' | 'clipboard') => { const { url } = match; const link = `https://velog.io${url}`; @@ -465,8 +417,8 @@ const PostViewer: React.FC = ({ } followButton={ } /> @@ -482,8 +434,8 @@ const PostViewer: React.FC = ({ ownPost={post.user.id === userId} followButton={ } /> diff --git a/src/lib/graphql/__data__/post.data.ts b/src/lib/graphql/__data__/post.data.ts index cc0332d2..3686a95b 100644 --- a/src/lib/graphql/__data__/post.data.ts +++ b/src/lib/graphql/__data__/post.data.ts @@ -22,6 +22,7 @@ export const postData: { post: SinglePost } = { user: { id: 'c76ccc50-b34d-11e8-b01f-598f1220d1c8', username: 'velopert', + is_followed: true, profile: { id: 'c7caf1e0-b34d-11e8-b01f-598f1220d1c8', display_name: 'Minjun Kim', @@ -177,6 +178,5 @@ export const postData: { post: SinglePost } = { }, }, }, - followed: false, }, }; diff --git a/src/lib/graphql/post.ts b/src/lib/graphql/post.ts index 8704a0d5..6cad2ed4 100644 --- a/src/lib/graphql/post.ts +++ b/src/lib/graphql/post.ts @@ -102,6 +102,7 @@ export interface SinglePost { user: { id: string; username: string; + is_followed: boolean; profile: { id: string; display_name: string; @@ -124,7 +125,6 @@ export interface SinglePost { liked: boolean; likes: number; linked_posts: LinkedPosts; - followed: boolean; } export interface CommentWithReplies { @@ -252,10 +252,10 @@ export const READ_POST = gql` url_slug likes liked - followed user { id username + is_followed profile { id display_name diff --git a/src/lib/graphql/user.ts b/src/lib/graphql/user.ts index 12e402da..1d8d8162 100644 --- a/src/lib/graphql/user.ts +++ b/src/lib/graphql/user.ts @@ -28,6 +28,7 @@ export type User = { is_certified: boolean; profile: UserProfile; velogConfig: VelogConfig | null; + is_followed: boolean; }; export const GET_CURRENT_USER = gql` diff --git a/src/pages/velog/UserPage.tsx b/src/pages/velog/UserPage.tsx index 2ba87b91..c9cc4b20 100644 --- a/src/pages/velog/UserPage.tsx +++ b/src/pages/velog/UserPage.tsx @@ -17,7 +17,8 @@ export interface UserPageProps const UserPage: React.FC = ({ match, location }) => { const { username, tab } = match.params; - + window.location.href = `${process.env + .REACT_APP_CLIENT_V3_HOST!}/@${username}/posts`; return ( From 766b5aa725b806e98a3885cc937a452dbcbdd0d5 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 29 Nov 2023 00:51:48 +0900 Subject: [PATCH 033/132] chore: rename follow button component --- .../PostFollowButton.tsx => common/FollowButton.tsx} | 10 +++++----- src/containers/post/PostViewer.tsx | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) rename src/components/{post/PostFollowButton.tsx => common/FollowButton.tsx} (95%) diff --git a/src/components/post/PostFollowButton.tsx b/src/components/common/FollowButton.tsx similarity index 95% rename from src/components/post/PostFollowButton.tsx rename to src/components/common/FollowButton.tsx index ef29181e..57def48e 100644 --- a/src/components/post/PostFollowButton.tsx +++ b/src/components/common/FollowButton.tsx @@ -14,7 +14,7 @@ export interface PostFollowButtonProps { followed: boolean; } -const PostFollowButton: React.FC = ({ +const FollowButton: React.FC = ({ followingUserId, followed, }) => { @@ -43,7 +43,7 @@ const PostFollowButton: React.FC = ({ setButtonText('팔로잉'); }; - const onClick = debounce(300, async () => { + const onClick = debounce(300, () => { if (loadingFollowUser || loadingUnfollowUser) return; const variables = { @@ -71,7 +71,7 @@ const PostFollowButton: React.FC = ({ __typename: 'User', }, }); - await unfollow({ variables }); + unfollow({ variables }); } else { client.writeFragment({ id: `User:${followingUserId}`, @@ -81,7 +81,7 @@ const PostFollowButton: React.FC = ({ __typename: 'User', }, }); - await follow({ variables }); + follow({ variables }); setButtonText('팔로잉'); } @@ -196,4 +196,4 @@ const FollowButtonBlock = styled.div<{ } `; -export default PostFollowButton; +export default FollowButton; diff --git a/src/containers/post/PostViewer.tsx b/src/containers/post/PostViewer.tsx index 2c400ef2..a6b34f9e 100644 --- a/src/containers/post/PostViewer.tsx +++ b/src/containers/post/PostViewer.tsx @@ -44,7 +44,7 @@ import optimizeImage from '../../lib/optimizeImage'; import { useSetShowFooter } from '../../components/velog/VelogPageTemplate'; import HorizontalBanner from './HorizontalBanner'; import gtag from '../../lib/gtag'; -import PostFollowButton from '../../components/post/PostFollowButton'; +import FollowButton from '../../components/common/FollowButton'; const UserProfileWrapper = styled(VelogResponsive)` margin-top: 16rem; @@ -266,7 +266,7 @@ const PostViewer: React.FC = ({ history.push(`/post-stats/${post.id}`); }; - const onLikeToggle = async () => { + const onLikeToggle = () => { if (loadingLike || loadingUnlike) return; const variables = { @@ -300,7 +300,7 @@ const PostViewer: React.FC = ({ __typename: 'Post', }, }); - await unlikePost({ + unlikePost({ variables, }); } else { @@ -313,7 +313,7 @@ const PostViewer: React.FC = ({ __typename: 'Post', }, }); - await likePost({ + likePost({ variables, }); } @@ -416,7 +416,7 @@ const PostViewer: React.FC = ({ /> } followButton={ - @@ -433,7 +433,7 @@ const PostViewer: React.FC = ({ username={post.user.username} ownPost={post.user.id === userId} followButton={ - From d2d553bbfe96d82cb7cc4f6dfbd304c5183b7070 Mon Sep 17 00:00:00 2001 From: carrick Date: Wed, 29 Nov 2023 01:22:30 +0900 Subject: [PATCH 034/132] feat: apply vlink to the velog page --- src/components/base/HeaderLogo.tsx | 9 ++++----- src/components/common/FlatPostCard.tsx | 9 +++++---- src/components/common/PostCard.tsx | 5 +++-- src/components/common/UserProfile.tsx | 10 +++++----- src/components/post/PostCommentItem.tsx | 10 +++++----- src/components/post/PostHead.tsx | 4 ++-- src/containers/velog/SeriesPosts.tsx | 8 ++++---- 7 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/base/HeaderLogo.tsx b/src/components/base/HeaderLogo.tsx index 4d365fd3..52b19d08 100644 --- a/src/components/base/HeaderLogo.tsx +++ b/src/components/base/HeaderLogo.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import styled from 'styled-components'; -import { Link } from 'react-router-dom'; import { Logo, VelogIcon } from '../../static/svg'; import { UserLogo } from '../../modules/header'; import { themedPalette } from '../../lib/styles/themes'; @@ -31,15 +30,15 @@ const HeaderLogo: React.FC = ({ } if (!userLogo) return
; if (!username) return
; - const velogPath = `/@${username}`; + const velogPath = `/@${username}/posts`; return ( - + {userLogo.title || createFallbackTitle(username)} - + ); }; @@ -75,7 +74,7 @@ const HeaderLogoBlock = styled.div` } `; -const VelogLogoLink = styled(Link)` +const VelogLogoLink = styled(VLink)` color: inherit; svg { diff --git a/src/components/common/FlatPostCard.tsx b/src/components/common/FlatPostCard.tsx index aac2c75c..8ab7b6fc 100644 --- a/src/components/common/FlatPostCard.tsx +++ b/src/components/common/FlatPostCard.tsx @@ -14,6 +14,7 @@ import media from '../../lib/styles/media'; import PrivatePostLabel from './PrivatePostLabel'; import optimizeImage from '../../lib/optimizeImage'; import { LikeIcon } from '../../static/svg'; +import VLink from './VLink'; const PostCardBlock = styled.div` padding-top: 4rem; @@ -150,7 +151,7 @@ const FlatPostCard = ({ post, hideUser }: PostCardProps) => { }; const url = `/@${post.user.username}/${post.url_slug}`; - const velogUrl = `/@${post.user.username}`; + const velogUrl = `/@${post.user.username}/posts`; if (!post.user.profile) { console.log(post); @@ -159,7 +160,7 @@ const FlatPostCard = ({ post, hideUser }: PostCardProps) => { {!hideUser && (
- + { )} alt="thumbnail" /> - +
- {post.user.username} + {post.user.username}
)} diff --git a/src/components/common/PostCard.tsx b/src/components/common/PostCard.tsx index f73f7660..21c278e3 100644 --- a/src/components/common/PostCard.tsx +++ b/src/components/common/PostCard.tsx @@ -14,6 +14,7 @@ import { mediaQuery } from '../../lib/styles/media'; import { Link } from 'react-router-dom'; import usePrefetchPost from '../../lib/hooks/usePrefetchPost'; import gtag from '../../lib/gtag'; +import VLink from './VLink'; export type PostCardProps = { post: PartialPost; @@ -73,7 +74,7 @@ function PostCard({ post, forHome, forPost }: PostCardProps) {