Skip to content

Commit

Permalink
firebase for persistance
Browse files Browse the repository at this point in the history
  • Loading branch information
tsmanuelanton committed Oct 24, 2023
1 parent 83b62bd commit 4e92a10
Show file tree
Hide file tree
Showing 16 changed files with 877 additions and 177 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@types/react-dom": "^18.0.6",
"astro": "^3.2.4",
"eslint-plugin-astro": "^0.29.1",
"firebase": "^10.5.0",
"lodash": "^4.17.21",
"react": "^18.0.0",
"react-dom": "^18.0.0",
Expand Down
70 changes: 43 additions & 27 deletions src/components/CommentSection.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,49 @@
import { useState, type FormEvent } from "react";
import { useState, type FormEvent, useEffect} from "react";
import type { PostComment as PostCommentType } from "../types/posts";
import Button from "./Button";
import getTimeAgo from "../utils/TimeAgo";
import type { User } from "@/types/user";

type Props = {
comments: PostCommentType[];
user: User
user: User;
};

const CommentSection = ({ comments: postComments, user }: Props) => {
const [comments, setComments] = useState(postComments);
const [text, setText] = useState<string>("");

const handleCommentBtn = (event: FormEvent<HTMLFormElement>) => {
setComments(
comments.concat({
id: crypto.randomUUID(),
user,
userID: user.id,
text,
created_at: new Date()
created_at: new Date(),
})
);
setText("")
event.preventDefault()
setText("");
event.preventDefault();
};

return (
<div>
<div className="max-h-80 overflow-y-scroll">
{comments?.map((comment) => (
<div key={comment.id} className="flex m-2 gap-2 mr-10">
<div className="flex-none w-8 p-0 m-0">
<img
className="rounded-full w-8"
src={comment.user.image}
alt="Profile image"
/>
</div>

<div>
<div className=" bg-gray-200 rounded-3xl p-2 px-3">
<p className="font-medium">{comment.user.name}</p>
<p className="break-all">{comment.text}</p>
</div>
<p className="flex justify-end text-xs text-gray-500">{getTimeAgo(comment.created_at)}</p>
</div>

</div>
<Comment key={comment.id} comment={comment} />
))}
</div>

<div className="sticky bg-white p-2 border-t">
<div className="flex space-x-2">
<img
className="w-12 rounded-full"
src="/img/minions.jpg"
src={user.image}
alt="Profile image"
/>
<form onSubmit={(e) => handleCommentBtn(e)} className="flex w-full gap-2">
<form
onSubmit={(e) => handleCommentBtn(e)}
className="flex w-full gap-2"
>
<input
value={text}
onChange={(e) => setText(e.target.value)}
Expand All @@ -81,3 +66,34 @@ const CommentSection = ({ comments: postComments, user }: Props) => {
};

export default CommentSection;

const Comment = ({ comment }: { comment: PostCommentType }) => {
const [user, setUser] = useState<User>();
useEffect(() => {
fetch(`${window.location.origin}/api/users?id=${comment.userID}`)
.then((res) => res.json())
.then((user) => setUser(user));
}, []);

return (
<div key={comment.id} className="flex m-2 gap-2 mr-10">
<div className="flex-none w-8 p-0 m-0">
<img
className="rounded-full w-8"
src={user?.image}
alt="Profile image"
/>
</div>

<div>
<div className=" bg-gray-200 rounded-3xl p-2 px-3">
<p className="font-medium">{user?.name}</p>
<p className="break-all">{comment.text}</p>
</div>
<p className="flex justify-end text-xs text-gray-500">
{getTimeAgo(comment.created_at)}
</p>
</div>
</div>
);
};
4 changes: 1 addition & 3 deletions src/components/LoginCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ const LoginCard = () => {

const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const { protocol, host } = window.location;
const baseUrl = protocol + "//" + host;
const res = await fetch(`${baseUrl}/api/login`, {
const res = await fetch(`${window.location.origin}/api/login`, {
method: "POST",
body: JSON.stringify({
email,
Expand Down
28 changes: 20 additions & 8 deletions src/components/PostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import type { User } from "../types/user";
import isEqual from "lodash/isEqual";
import Button from "./Button";
import CommentSection from "./CommentSection";
import { ChatBubbleLeftIcon, HandThumbUpIcon, ShareIcon } from "@heroicons/react/24/outline";
import {
ChatBubbleLeftIcon,
HandThumbUpIcon,
ShareIcon,
} from "@heroicons/react/24/outline";
import { HandThumbUpIcon as HandThumbUpIconSolid } from "@heroicons/react/24/solid";

const PostCard = ({ post, user }: { post: PostType; user: User }) => {
Expand All @@ -17,8 +21,16 @@ const PostCard = ({ post, user }: { post: PostType; user: User }) => {
})
);
const [visibleComments, setVisibleComments] = useState(false);
const [postOwner, setPostOwner] = useState<User>();

useEffect(() => {
const { protocol, host } = window.location;
const baseUrl = protocol + "//" + host;
fetch(`${baseUrl}/api/users?id=${post.userID}`)
.then((res) => res.json())
.then((postOwner) => setPostOwner(postOwner))
.catch(console.error);

const intervalID = setInterval(
() => setTimeAgo(getTimeAgo(post.created_at)),
1000 * 60
Expand All @@ -28,12 +40,10 @@ const PostCard = ({ post, user }: { post: PostType; user: User }) => {
}, []);

const handleLikeBtn = () => {
let currentUserIndex = likes.findIndex((element) => {
return isEqual(element, user);
});
let currentUserIndex = likes.findIndex((userId) => userId === user.id);

if (currentUserIndex === -1) {
setLikes(likes.concat(user));
setLikes(likes.concat(user.id));
setPostLiked(true);
} else {
likes.splice(currentUserIndex, 1);
Expand All @@ -47,11 +57,11 @@ const PostCard = ({ post, user }: { post: PostType; user: User }) => {
<div className="flex space-x-2">
<img
className="w-12 rounded-full"
src={post.user.image}
src={postOwner?.image}
alt="Profile image"
/>
<div>
<p className="font-medium">{post.user.name}</p>
<p className="font-medium">{postOwner?.name}</p>
<p className="text-sm font-medium text-gray-500">{timeAgo}</p>
</div>
</div>
Expand Down Expand Up @@ -93,7 +103,9 @@ const PostCard = ({ post, user }: { post: PostType; user: User }) => {
Compartir
</Button>
</div>
{visibleComments && <CommentSection user={user} comments={post.feedback.comments} />}
{visibleComments && (
<CommentSection user={user} comments={post.feedback.comments} />
)}
</div>
);
};
Expand Down
17 changes: 11 additions & 6 deletions src/components/PostCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useState } from "react";
import type {
Post as PostType,
PostBody as PostBodyType,
Post,
} from "../types/posts";
import type { User } from "../types/user";
import NewPostCard from "./NewPostCard";
Expand All @@ -13,16 +14,17 @@ type Props = {
};

const Posts = ({ user, posts: initialPosts }: Props) => {
const [posts, setPosts] = useState(initialPosts);
const [posts, setPosts] = useState<Post[]>(initialPosts);

const addPost = async (body: PostBodyType) => {
const post: PostType = {
id: crypto.randomUUID(),
user,
userID: user.id,
created_at: new Date(),
body,
feedback: { likes: [], comments: [] },
};

const { protocol, host } = window.location;
const baseUrl = `${protocol}//${host}`;

Expand All @@ -33,14 +35,17 @@ const Posts = ({ user, posts: initialPosts }: Props) => {
}).catch(console.error);

const res = await fetch(baseUrl + "/api/posts");
const posts = await res.json();
setPosts(posts);

if (res.ok){
const newPosts : Post[] = await res.json();
setPosts(newPosts);
}
};

return (
<div className="flex flex-col">
<div className="flex flex-col space-y-4">
<NewPostCard user={user} addPost={addPost} />
<div className="flex flex-col-reverse space-y-4">
<div className="flex flex-col space-y-4">
{posts.map((post) => (
<PostCard key={post.id} post={post} user={user} />
))}
Expand Down
23 changes: 13 additions & 10 deletions src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ interface Props {
navbarHidden?: boolean;
}
const { title, navbarHidden } = Astro.props;
const url = Astro.url;
const {origin} = Astro.url
const loggedUserId = Astro.cookies.get("loggedUser")?.value
const user = await fetch(`${origin}/api/users?id=${loggedUserId}`).then(res => res.json())
const {url, cookies} = Astro;
let user;
const loggedUserId = cookies.get("loggedUser")?.value;
if (loggedUserId)
user = await fetch(`${url.origin}/api/users?id=${loggedUserId}`).then((res) => res.json());
---

<!doctype html>
Expand All @@ -24,12 +26,13 @@ const user = await fetch(`${origin}/api/users?id=${loggedUserId}`).then(res => r
<ViewTransitions />
</head>
<body>
{!navbarHidden && <NavBar client:load currentUrl={url} user={user}/>}
{!navbarHidden && <NavBar client:load currentUrl={url} user={user} />}

<slot />
</body><style is:global>
html {
background-color: #f0f2f5;
}
</style>
<style is:global>
html {
background-color: #f0f2f5;
}
</style>
</body>
</html>
20 changes: 20 additions & 0 deletions src/lib/firebase/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// import { getAnalytics } from "firebase/analytics";
import { getFirestore } from "firebase/firestore";

// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyCHZ_KT-ewZloyK0M9x0vr1zVXdnJSYBew",
authDomain: "facebook-clone-uo276213.firebaseapp.com",
projectId: "facebook-clone-uo276213",
storageBucket: "facebook-clone-uo276213.appspot.com",
messagingSenderId: "73250121069",
appId: "1:73250121069:web:dda0c0b09b9c4d1b816664",
measurementId: "G-BCVMQBQL8W",
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// const analytics = getAnalytics(app);
export const db = getFirestore(app);
59 changes: 59 additions & 0 deletions src/lib/firebase/firestore/posts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Post, PostComment } from "@/types/posts";
import {
doc,
query,
getDoc,
getDocs,
collection,
addDoc,
orderBy
} from "firebase/firestore";
import { db } from "../client";

const postsCollection = collection(db, "posts");

export const getPost = async (id: string) => {
const ref = doc(db, "posts", id);
return getDoc(ref);
};

export const getPosts = async () => {
return getDocs(query(postsCollection, orderBy("created_at", "desc"))).then(({ docs }) =>
docs.map((doc) => {

const { user: userRef, created_at } = doc.data();
const postOwnerID = userRef.id;
const likes = doc.data().feedback.likes.map(({ id }: any) => id);
const comments: PostComment[] = doc
.data()
.feedback.comments.map((data: any) => ({
id: data.id,
userID: data.user.id,
text: data.text,
created_at: data.created_at.toDate(),
}));

const post: Post = {
id: doc.id,
userID: postOwnerID,
created_at: created_at.toDate(),
body: doc.data().body,
feedback: {
likes,
comments,
},
};
return post;
})
);
};

export const addPost = async (post: Post) => {
const { userID, created_at, ...rest } = post;
const docRef = await addDoc(postsCollection, {
user: doc(db, "/users/" + userID),
created_at: new Date(post.created_at),
...rest,
});
return docRef.id;
};
Loading

0 comments on commit 4e92a10

Please sign in to comment.