1. 기존의 데이터를 모두 삭제한다.
2. 코드를 수정한다.
tweet.tsx
import styled from "styled-components";
import { ITweet } from "./timeline";
import { auth, db, storeage } from "../routes/firebase";
import { deleteDoc, doc } from "firebase/firestore";
import { deleteObject, ref } from "firebase/storage";
const Wrapper = styled.div`
display: grid;
grid-template-columns: 3fr 1fr;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.5);
border-radius: 15px;
`;
const Column = styled.div``;
const Photo = styled.img`
width: 100px;
height: 100px;
border-radius: 15px;
`;
const Username = styled.span`
font-weight: 600;
font-size: 15px;
`;
const Payload = styled.p`
margin: 10px 0px;
font-size: 18px;
`;
const DeleteButton = styled.button`
background-color: tomato;
color: white;
font-weight: 600;
border: 0;
font-size: 12px;
padding: 5px 10px;
text-transform: uppercase;
border-radius: 5px;
cursor: pointer;
`;
export default function Tweet({username, photo, tweet, userId, id} : ITweet){
const user = auth.currentUser;
const onDelete = async() => {
const ok = confirm("Are you sure you want to delete this tweet?");
if(!ok || user?.uid !== userId){
return;
};
try {
await deleteDoc(doc(db, "tweets", id));
if(photo){
const photoRef = ref(storeage, `tweets/${user.uid}/${id}`);
//생성할때의 경로와 같다!!!
await deleteObject(photoRef);
};
} catch (e) {
}finally{
}
};
return <Wrapper>
<Column>
<Username>{username}</Username>
<Payload>{tweet}</Payload>
{user?.uid === userId ? <DeleteButton onClick={onDelete}>Delete</DeleteButton> : null}
</Column>
{photo ? (
<Column>
<Photo src = {photo}/>
</Column>
) : null}
</Wrapper>
};
post-tweet-form.tsx
import { addDoc, collection, updateDoc } from "firebase/firestore";
import { useState } from "react";
import styled from "styled-components"
import { auth, db, storeage } from "../routes/firebase";
import { getDownloadURL, ref, uploadBytes } from "firebase/storage";
const Form = styled.form`
display: flex;
flex-direction: column;
gap: 10px;
`;
const TextArea = styled.textarea`
border: 2px solid white;
padding: 20px;
border-radius: 20px;
font-size: 16px;
color: white;
background-color: black;
width: 100%;
resize: none;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
&::placeholder {
font-size: 16px;
}
&:focus {
outline: none;
border-color: #1d9bf0;
}
`;
const AttachFileButton = styled.label`
padding: 10px 0px;
color: #1d9bf0;
text-align: center;
border-radius: 20px;
border: 1px solid #1d9bf0;
font-size: 14px;
font-weight: 600;
cursor: pointer;
`;
const AttachFileInput = styled.input`
display: none;
`;
const SubmitBtn = styled.input`
background-color: #1d9bf0;
color: white;
border: none;
padding: 10px 0px;
border-radius: 20px;
font-size: 16px;
cursor: pointer;
&:hover,
&:active {
opacity: 0.9;
}
`;
export default function PostTweetForm(){
const [isLoading, setLoading] = useState(false);
const [tweet, setTweet] = useState("");
const [file, setFile] = useState<File|null>(null);
const onChange = (e : React.ChangeEvent<HTMLTextAreaElement>) => {
setTweet(e.target.value);
};
const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const {files} = e.target;
if(files && files.length === 1){
setFile(files[0]);
}
};
const onSubmit = async (e:React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const user = auth.currentUser;
if(!user || tweet === "" || tweet.length > 180){
return;
}
try {
setLoading(true);
const doc = await addDoc(collection(db, "tweets"), {
tweet,
createAt : Date.now(),
username : user.displayName || "Anonymous",
userId : user.uid
});
if(file){
const locationRef = ref(storeage, `tweets/${user.uid}/${doc.id}`);
const result = await uploadBytes(locationRef, file);
const url = await getDownloadURL(result.ref);
await updateDoc(doc, {photo : url});
}
setTweet("");
setFile(null);
} catch (e) {
console.log(e);
}finally{
setLoading(false);
}
};
return <Form onSubmit={onSubmit}>
<TextArea onChange={onChange} value={tweet} placeholder="What is happening?"/>
<AttachFileButton htmlFor="file">{file ? "Photo added ✅" : "Add photo"}</AttachFileButton>
<AttachFileInput onChange={onFileChange} type="file" id="file" accept="image/*"/>
<SubmitBtn type="submit" value={isLoading ? "Posting..." : "Post Tweet"}/>
</Form>
};
3. 테스트를 해본다.
nwitter-reloaded.z01
19.53MB
nwitter-reloaded.z02
19.53MB
nwitter-reloaded.z03
19.53MB
nwitter-reloaded.z04
19.53MB
nwitter-reloaded.z05
19.53MB
nwitter-reloaded.zip
15.59MB
'트위터(React, TypeScript, Firebase, Vite)' 카테고리의 다른 글
21. User's Timeline (0) | 2025.04.22 |
---|---|
20. USER PROFILE - User Avartar (0) | 2025.04.21 |
18. TWEETING - Realtime [2] (0) | 2025.04.17 |
17. TWEETING - Realtime [1] (0) | 2025.04.17 |
16. TWEETING - Fetching Timeline (0) | 2025.04.17 |