Skip to content

Commit

Permalink
[๐Ÿฅ : feat] ํƒ€์ž„๋ผ์ธ - ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋…ธ์ถœ
Browse files Browse the repository at this point in the history
- ํšŒ์›๊ฐ€์ž… ์‹œ, ์œ ์ €์˜ ์ •๋ณด๋ฅผ ๋‹ด๋Š” user ์ปฌ๋ ‰์…˜ ์ƒ์„ฑ. ์—ฌ๊ธฐ์— userAvatar๋กœ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์ €์žฅํ•œ ๋’ค ๊ด€๋ฆฌํ•˜๋Š” ํ˜•์‹ (+ ์†Œ์…œ ๋กœ๊ทธ์ธ ์ž‘์—… ํ•„์š”)
- ์ตœ์‹  ํ”„๋กœํ•„ ์ด๋ฏธ์ง€๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ๋…ธ์ถœ
- ๊ธฐํƒ€ ์Šคํƒ€์ผ๋ง ์ž‘์—…
  • Loading branch information
sryung1225 committed Dec 14, 2023
1 parent c3a3c44 commit 75ed77b
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 52 deletions.
9 changes: 8 additions & 1 deletion src/components/signUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { FirebaseError } from 'firebase/app';
import { createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
import { auth } from '../firebase.ts';
import { doc, setDoc } from 'firebase/firestore';
import { auth, db } from '../firebase.ts';
import * as S from '../styles/auth.ts';
import * as P from '../styles/popup.ts';
import ImageComputer from '../assets/images/logo-small.png';
Expand Down Expand Up @@ -63,6 +64,12 @@ export default function SignUp({ onClose }: ISignUpProps) {
await updateProfile(credentials.user, {
displayName: userName,
});
const userRef = doc(db, 'users', credentials.user.uid);
await setDoc(userRef, {
userName: userName || 'Anonymous',
userId: credentials.user.uid,
userAvatar: credentials.user.photoURL || null,
});
navigate('/');
} catch (error) {
if (error instanceof FirebaseError) {
Expand Down
39 changes: 26 additions & 13 deletions src/components/tweet.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useState } from 'react';
import { deleteDoc, doc } from 'firebase/firestore';
import { useEffect, useState } from 'react';
import { deleteDoc, doc, getDoc } from 'firebase/firestore';
import { deleteObject, ref } from 'firebase/storage';
import { auth, db, storage } from '../firebase.ts';
import ITweet from '../interfaces/ITweet.ts';
import FormattedDate from '../utils/formattedDate.tsx';
import * as S from '../styles/tweet.ts';
import * as P from '../styles/popup.ts';
import { ReactComponent as IconUser } from '../assets/images/i-user.svg';

export default function Tweet({
id,
Expand All @@ -16,6 +17,12 @@ export default function Tweet({
tweet,
}: ITweet) {
const user = auth.currentUser;
const [userAvatar, setUserAvatar] = useState<string | null>(null);
const fetchUserAvatar = async () => {
const userDoc = await getDoc(doc(db, 'users', userId));
const userData = userDoc.data();
setUserAvatar(userData?.userAvatar || null);
};
const [deletePopup, setDeletePopup] = useState(false);
const toggleDeletePopup = () => {
setDeletePopup(!deletePopup);
Expand All @@ -34,20 +41,26 @@ export default function Tweet({
//
}
};
useEffect(() => {
fetchUserAvatar();
}, [userId, userAvatar]);
return (
<S.Wrapper hasPhoto={!!photo}>
<S.Column>
<S.Wrapper>
<S.Avatar>
{userAvatar ? <S.AvatarImage src={userAvatar} /> : <IconUser />}
</S.Avatar>
<S.Row>
<S.Username>{userName}</S.Username>
<S.Date>{FormattedDate(createdAt)}</S.Date>
<S.Payload>{tweet}</S.Payload>
{user?.uid === userId ? (
<S.DeleteButton onClick={toggleDeletePopup}>์‚ญ์ œ</S.DeleteButton>
) : null}
</S.Column>
{photo ? (
<S.Column>
<S.Photo src={photo} />
</S.Column>
</S.Row>
<S.Payload>{tweet}</S.Payload>
{photo ? <S.Photo src={photo} /> : null}
{user?.uid === userId ? (
<>
<S.DeleteButton onClick={toggleDeletePopup} type="button">
<span className="a11yHidden">ํฌ์ŠคํŒ… ์‚ญ์ œํ•˜๊ธฐ</span>
</S.DeleteButton>
</>
) : null}
{deletePopup ? (
<P.PopupWrapper>
Expand Down
10 changes: 9 additions & 1 deletion src/routes/profile.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useState } from 'react';
import { getDownloadURL, ref, uploadBytes } from 'firebase/storage';
import { updateProfile } from 'firebase/auth';
import { auth, storage } from '../firebase.ts';
import { doc, updateDoc } from 'firebase/firestore';
import { auth, db, storage } from '../firebase.ts';
import WindowTop from '../components/window-top.tsx';
import UserTimeline from '../components/user-timeline.tsx';
import * as W from '../styles/window.ts';
Expand All @@ -11,6 +12,12 @@ import { ReactComponent as IconUser } from '../assets/images/i-user.svg';
export default function Profile() {
const user = auth.currentUser;
const [avatar, setAvatar] = useState(user?.photoURL);
const updateUserAvatar = async (uid: string, newAvatarUrl: string) => {
const userDocRef = doc(db, 'users', uid);
await updateDoc(userDocRef, {
userAvatar: newAvatarUrl,
});
};
const onAvatarChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const { files } = e.target;
if (!user) return;
Expand All @@ -23,6 +30,7 @@ export default function Profile() {
await updateProfile(user, {
photoURL: avatarUrl,
});
await updateUserAvatar(user.uid, avatarUrl);
}
};
return (
Expand Down
2 changes: 1 addition & 1 deletion src/styles/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const Logo = styled.div`

export const LogoTitle = styled.h1`
color: ${whiteColor};
font-size: 30px;
font-size: 34px;
text-shadow: ${LogoTextShadow(2)};
span {
color: ${primaryColor};
Expand Down
21 changes: 8 additions & 13 deletions src/styles/popup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,29 @@ export const PopupWrapper = styled.div`
background-color: rgba(0, 0, 0, 0.4);
`;

export const Popup = styled.div`
export const PopupBox = styled.div`
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: calc(100vw - 100px);
padding: 30px;
background-color: ${whiteColor};
border: 3px solid ${blackColor};
`;

export const Popup = styled(PopupBox)`
max-width: 757px;
height: calc(100vh - 100px);
max-height: 728px;
padding: 30px;
background-color: ${whiteColor};
border-radius: 10px;
`;

export const MiniPopup = styled.div`
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: calc(100vw - 100px);
export const MiniPopup = styled(PopupBox)`
max-width: 400px;
height: auto;
padding: 30px;
background-color: ${whiteColor};
border-radius: 6px;
border: 3px solid ${blackColor};
`;

export const CloseButton = styled.button`
Expand Down
2 changes: 1 addition & 1 deletion src/styles/post-tweet-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const Form = styled.form`
flex-shrink: 0;
gap: 10px;
width: 100%;
padding-bottom: 10px;
padding-bottom: 20px;
&::after {
content: '';
position: absolute;
Expand Down
13 changes: 12 additions & 1 deletion src/styles/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@ import { styled } from 'styled-components';
import { grayColor } from './global.ts';

export const Avatar = styled.div`
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
margin: 50px 0;
padding: 50px 0;
&::after {
content: '';
position: absolute;
bottom: 0;
left: -10px;
right: -10px;
width: calc(100% + 20px);
height: 2px;
background-color: #070707;
}
`;

export const AvatarUpload = styled.label`
Expand Down
1 change: 1 addition & 0 deletions src/styles/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styled from 'styled-components';

export const TimelineWrapper = styled.ul`
display: block;
margin-top: 10px;
overflow-y: auto;
`;

Expand Down
107 changes: 86 additions & 21 deletions src/styles/tweet.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,53 @@
import { styled } from 'styled-components';
import { grayColor, primaryColor, whiteColor } from './global.ts';
import { grayColor, primaryColor } from './global.ts';

interface IWrapperProps {
hasPhoto: boolean;
}

export const Wrapper = styled.li<IWrapperProps>`
display: grid;
grid-template-columns: ${({ hasPhoto }) => (hasPhoto ? '3fr 1fr' : '1fr')};
padding: 20px;
margin: 20px 0;
export const Wrapper = styled.li`
position: relative;
display: flex;
flex-direction: column;
padding: 20px 20px 20px 60px;
&:not(:last-child) {
border-bottom: 1px dashed ${grayColor};
}
`;

export const Column = styled.div``;
export const Row = styled.div``;

export const Photo = styled.img`
width: 100px;
height: 100px;
border-radius: 15px;
export const Avatar = styled.div`
position: absolute;
top: 20px;
left: 10px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
width: 40px;
height: 40px;
border-radius: 50%;
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 36px;
height: 36px;
border: 2px dashed ${grayColor};
border-radius: 50%;
}
svg {
width: 26px;
height: 26px;
stroke: ${grayColor};
}
`;

export const AvatarImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
z-index: 10;
`;

export const Username = styled.span`
Expand All @@ -39,11 +66,49 @@ export const Payload = styled.p`
font-size: 18px;
`;

export const Photo = styled.img`
width: 300px;
height: 300px;
border-radius: 15px;
`;

export const DeleteButton = styled.button`
padding: 5px 10px;
background-color: ${primaryColor};
border: 0;
border-radius: 5px;
color: ${whiteColor};
font-size: 12px;
position: absolute;
top: 16px;
right: 20px;
width: 25px;
height: 25px;
background-color: transparent;
border: none;
&::before,
&::after {
content: '';
position: absolute;
top: 11px;
left: 6px;
width: 13px;
height: 2px;
background-color: ${primaryColor};
}
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(135deg);
}
`;

export const EditButton = styled.button`
position: absolute;
top: 16px;
right: 50px;
width: 25px;
height: 25px;
background-color: transparent;
border: none;
svg {
width: 16px;
height: 16px;
stroke: ${primaryColor};
}
`;

0 comments on commit 75ed77b

Please sign in to comment.