Skip to content

Commit

Permalink
Merge pull request #11 from sryung1225/dev
Browse files Browse the repository at this point in the history
포스팅 수정하기 기능 추가 (#1 #6) & 로딩 스피너 개편 (#10)
  • Loading branch information
sryung1225 authored Dec 18, 2023
2 parents e69f52f + 8bf37ba commit 510baf8
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Profile from './routes/profile.tsx';
import SearchResult from './routes/search-result.tsx';
import Auth from './routes/auth.tsx';
import Layout from './components/layout.tsx';
import LoadingScreen from './components/loading-screen.tsx';
import LoadingSpinner from './components/loading-spinner.tsx';
import * as S from './styles/global.ts';

const router = createBrowserRouter([
Expand Down Expand Up @@ -51,7 +51,7 @@ function App() {
return (
<>
<S.GlobalStyles />
{isLoading ? <LoadingScreen /> : <RouterProvider router={router} />}
{isLoading ? <LoadingSpinner /> : <RouterProvider router={router} />}
</>
);
}
Expand Down
3 changes: 3 additions & 0 deletions src/assets/images/i-edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions src/assets/images/loading-spinner-mini.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 64 additions & 0 deletions src/assets/images/loading-spinner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions src/components/edit-tweet-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState } from 'react';
import { deleteField, doc, updateDoc } from 'firebase/firestore';
import {
deleteObject,
getDownloadURL,
ref,
uploadBytes,
} from 'firebase/storage';
import { auth, db, storage } from '../firebase.ts';
import ITweet from '../interfaces/ITweet.ts';
import * as S from '../styles/tweet-form.ts';
import { ReactComponent as IconPhoto } from '../assets/images/i-photo.svg';
import { ReactComponent as LoadingSpinner } from '../assets/images/loading-spinner-mini.svg';

interface IEditTweetForm extends Pick<ITweet, 'id' | 'tweet' | 'photo'> {
onClose: () => void;
}

export default function EditTweetForm({
id,
tweet: initialTweet,
photo: initialPhoto,
onClose,
}: IEditTweetForm) {
const [isLoading, setLoading] = useState(false);
const [tweet, setTweet] = useState(initialTweet);
const [image, setImage] = useState<File | null>(null);
const [imagePreview, setImagePreview] = useState(initialPhoto);

const onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setTweet(e.target.value);
};
const onImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const images = e.target.files;
if (images && images.length === 1) {
setImage(images[0]);
const previewUrl = URL.createObjectURL(images[0]);
setImagePreview(previewUrl);
}
};
const onImageDelete = () => {
setImage(null);
setImagePreview('');
};
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const user = auth.currentUser;
if (!user || isLoading || tweet === '' || tweet.length > 180) return;
try {
setLoading(true);
const tweetDocRef = doc(db, 'tweets', id);
await updateDoc(tweetDocRef, {
tweet,
});
if (image) {
const locationRef = ref(
storage,
initialPhoto || `tweets/${user.uid}/${id}`,
);
const result = await uploadBytes(locationRef, image);
const url = await getDownloadURL(result.ref);
await updateDoc(tweetDocRef, {
photo: url,
});
} else if (!image && initialPhoto && initialPhoto !== imagePreview) {
const locationRef = ref(storage, initialPhoto);
await deleteObject(locationRef);
await updateDoc(tweetDocRef, {
photo: deleteField(),
});
}
setImage(null);
} catch (error) {
console.log(error);
} finally {
setLoading(false);
onClose();
}
};
return (
<S.EditForm onSubmit={onSubmit}>
<S.TextArea
onChange={onChange}
value={tweet}
rows={5}
maxLength={180}
placeholder="지금 무슨 일이 일어나고 있나요?"
/>
{imagePreview ? (
<>
<S.AttachImagePreview src={imagePreview} alt="첨부이미지 미리보기" />
<S.AttachImageDelete type="button" onClick={onImageDelete} />
</>
) : (
<S.AttachImageButton htmlFor="image_edit">
<IconPhoto />
</S.AttachImageButton>
)}
<S.AttachImageInput
onChange={onImageChange}
type="file"
id="image_edit"
accept="image/*"
/>
<S.SubmitButton type="submit">
{isLoading ? <LoadingSpinner /> : '수정'}
</S.SubmitButton>
</S.EditForm>
);
}
9 changes: 0 additions & 9 deletions src/components/loading-screen.tsx

This file was deleted.

10 changes: 10 additions & 0 deletions src/components/loading-spinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Wrapper from '../styles/loading-spinner.ts';
import { ReactComponent as Spinner } from '../assets/images/loading-spinner.svg';

export default function LoadingSpinner() {
return (
<Wrapper>
<Spinner />
</Wrapper>
);
}
9 changes: 5 additions & 4 deletions src/components/post-tweet-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import React, { useState } from 'react';
import { addDoc, collection, updateDoc } from 'firebase/firestore';
import { getDownloadURL, ref, uploadBytes } from 'firebase/storage';
import { auth, db, storage } from '../firebase.ts';
import * as S from '../styles/post-tweet-form.ts';
import * as S from '../styles/tweet-form.ts';
import { ReactComponent as IconPhoto } from '../assets/images/i-photo.svg';
import { ReactComponent as LoadingSpinner } from '../assets/images/loading-spinner-mini.svg';

export default function PostTweetForm() {
const [isLoading, setLoading] = useState(false);
Expand Down Expand Up @@ -56,7 +57,7 @@ export default function PostTweetForm() {
}
};
return (
<S.Form onSubmit={onSubmit}>
<S.PostForm onSubmit={onSubmit}>
<S.TextArea
onChange={onChange}
value={tweet}
Expand All @@ -81,8 +82,8 @@ export default function PostTweetForm() {
accept="image/*"
/>
<S.SubmitButton type="submit">
{isLoading ? '포스팅 중...' : '포스팅'}
{isLoading ? <LoadingSpinner /> : '포스팅'}
</S.SubmitButton>
</S.Form>
</S.PostForm>
);
}
3 changes: 2 additions & 1 deletion src/components/signIn.tsx → src/components/sign-in.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { auth } 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';
import { ReactComponent as LoadingSpinner } from '../assets/images/loading-spinner-mini.svg';

interface ISignInProps {
onClose: () => void;
Expand Down Expand Up @@ -90,7 +91,7 @@ export default function SignIn({ onClose }: ISignInProps) {
required
/>
<S.SubmitButton type="submit">
{isLoading ? '로딩...' : '로그인하기'}
{isLoading ? <LoadingSpinner /> : '로그인하기'}
</S.SubmitButton>
</S.Form>
{firebaseError !== '' ? <S.Error>{firebaseError}</S.Error> : null}
Expand Down
3 changes: 2 additions & 1 deletion src/components/signUp.tsx → src/components/sign-up.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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';
import { ReactComponent as LoadingSpinner } from '../assets/images/loading-spinner-mini.svg';

interface ISignUpProps {
onClose: () => void;
Expand Down Expand Up @@ -116,7 +117,7 @@ export default function SignUp({ onClose }: ISignUpProps) {
required
/>
<S.SubmitButton type="submit">
{isLoading ? '로딩...' : '가입하기'}
{isLoading ? <LoadingSpinner /> : '가입하기'}
</S.SubmitButton>
</S.Form>
{firebaseError !== '' ? <S.Error>{firebaseError}</S.Error> : null}
Expand Down
File renamed without changes.
Empty file added src/components/tweet-form.tsx
Empty file.
25 changes: 24 additions & 1 deletion src/components/tweet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ 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 EditTweetForm from './edit-tweet-form.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';
import { ReactComponent as IconEdit } from '../assets/images/i-edit.svg';

export default function Tweet({
id,
Expand All @@ -23,6 +25,10 @@ export default function Tweet({
const userData = userDoc.data();
setUserAvatar(userData?.userAvatar || null);
};
const [editPopup, setEditPopup] = useState(false);
const toggleEditPopup = () => {
setEditPopup(!editPopup);
};
const [deletePopup, setDeletePopup] = useState(false);
const toggleDeletePopup = () => {
setDeletePopup(!deletePopup);
Expand All @@ -43,7 +49,7 @@ export default function Tweet({
};
useEffect(() => {
fetchUserAvatar();
}, [userId, userAvatar]);
}, [userName, userAvatar]);
return (
<S.Wrapper>
<S.Avatar>
Expand All @@ -57,11 +63,28 @@ export default function Tweet({
{photo ? <S.Photo src={photo} /> : null}
{user?.uid === userId ? (
<>
<S.EditButton onClick={toggleEditPopup} type="button">
<span className="a11yHidden">포스팅 수정하기</span>
<IconEdit />
</S.EditButton>
<S.DeleteButton onClick={toggleDeletePopup} type="button">
<span className="a11yHidden">포스팅 삭제하기</span>
</S.DeleteButton>
</>
) : null}
{editPopup ? (
<P.PopupWrapper>
<P.Popup>
<P.CloseButton onClick={toggleEditPopup} type="button" />
<EditTweetForm
id={id}
tweet={tweet}
photo={photo}
onClose={() => setEditPopup(false)}
/>
</P.Popup>
</P.PopupWrapper>
) : null}
{deletePopup ? (
<P.PopupWrapper>
<P.MiniPopup>
Expand Down
Loading

0 comments on commit 510baf8

Please sign in to comment.