Skip to content

Commit

Permalink
feat: add comment, detail view, logos
Browse files Browse the repository at this point in the history
  • Loading branch information
thraizz committed Jan 27, 2024
1 parent fac3619 commit 5b040f7
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 10 deletions.
70 changes: 70 additions & 0 deletions src/comments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { collection, getDocs } from "firebase/firestore";
import { defineStore } from "pinia";
import { ref } from "vue";

import { firestore } from "./firebase";
import { Comment } from "./types";

export const useCommentStore = defineStore("comments", () => {
const comments = ref<Comment[]>([]);

const fetchComments = () => {
const commentCollection = collection(firestore, "comments");

return getDocs(commentCollection)
.then((querySnapshot) => {
return querySnapshot.docs.map(
(doc) =>
({
_id: doc.id,
...doc.data(),
}) as Comment,
);
})
.catch((error) => {
console.log("Error getting documents: ", error);

return [] as Comment[];
});
};

const refetch = () => {
fetchComments().then((data) => {
comments.value = data;
});
};
refetch();

const getCommentsByProjectUid = (projectUid: string) => {
return comments.value.filter((comment) => comment.projectId === projectUid);
};

// function upvoteProject(_id: string, uid?: string) {
// const project = comments.value.find((p) => p._id === _id);
// if (!project) return;
// const projectData = {
// ...project,
// upvotes: uid
// ? project.upvotes.includes(uid)
// ? project.upvotes.filter((projectUid) => projectUid !== uid)
// : [...project.upvotes, uid]
// : project.upvotes,
// };
// setDoc(doc(firestore, `projects/${_id}`), projectData)
// .then(() => {
// comments.value = comments.value.map((p) =>
// p._id === _id ? projectData : p,
// );
// // refetch();
// })
// .catch((error) => {
// console.error("Error writing document: ", error);
// });
// }

return {
projects: comments,
refetch,
getCommentsByProjectUid,
};
});
5 changes: 4 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@ export type Project = {
images: string[]; // store links or references
textContent: string;
upvotes: string[];
comments: Comment[];
createdAt: Date;
updatedAt?: Date;
links?: string[];
logo: string;
};

// Comment Type
export type Comment = {
_id: string;
commentId: string;
userId: string; // author's user ID
projectId: string; // associated project ID
textContent: string;
timestamp: Date;
upvotes: string[];
};

// Database Collections
Expand Down
79 changes: 79 additions & 0 deletions src/views/AddCommentForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script setup lang="ts">
import { useField, useForm } from "vee-validate";
import { string } from "yup";
import { useCommentStore } from "@/comments";
const commentStore = useCommentStore();
const props = defineProps<{
projectUid: string;
}>();
type FormData = {
comment: string;
};
const { handleSubmit } = useForm<FormData>({
validationSchema: {
comment: string().required("Please enter a comment."),
},
initialValues: {
comment: "",
},
});
const onSubmit = handleSubmit(
// Success
(values: FormData) => {
// handle form submission here
commentStore.addCommentToProject(values.comment, props.projectUid);
},
// Failure
(errors) => {
console.log(errors);
},
);
const { value: comment, errorMessage: commentError } =
useField<string>("comment");
</script>

<template>
<div class="mt-6 flex gap-x-3">
<img
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""
class="h-6 w-6 flex-none rounded-full bg-gray-50"
/>

<div class="w-full">
<form class="relative flex-auto" @submit="onSubmit">
<div
class="overflow-hidden rounded-lg pb-12 shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-indigo-600"
>
<label for="comment" class="sr-only">Add your comment</label>

<textarea
id="comment"
v-model="comment"
rows="2"
name="comment"
class="block w-full resize-none border-0 bg-transparent py-1.5 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
placeholder="Add your comment..."
/>
</div>

<div
class="absolute inset-x-0 bottom-0 flex justify-between py-2 pl-3 pr-2"
>
<button
type="submit"
class="rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
>
Comment
</button>
</div>
</form>

<p v-if="commentError" class="error">{{ commentError }}</p>
</div>
</div>
</template>
67 changes: 67 additions & 0 deletions src/views/Comments.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<script setup lang="ts">
import { computed } from "vue";
import { useCommentStore } from "@/comments";
import AddCommentForm from "./AddCommentForm.vue";
const props = defineProps<{
projectUid: string;
}>();
const commentStore = useCommentStore();
const activity = computed(() =>
commentStore.getCommentsByProjectUid(props.projectUid),
);
</script>

<template>
<ul v-if="activity.length > 0" role="list" class="mt-6 space-y-6">
<li
v-for="(comment, activityItemIdx) in activity"
:key="comment._id"
class="relative flex gap-x-4"
>
<div
:class="[
activityItemIdx === activity.length - 1 ? 'h-6' : '-bottom-6',
'absolute left-0 top-0 flex w-6 justify-center',
]"
>
<div class="w-px bg-gray-200" />
</div>

<img
:src="comment.person.imageUrl"
alt=""
class="relative mt-3 h-6 w-6 flex-none rounded-full bg-gray-50"
/>

<div class="flex-auto rounded-md p-3 ring-1 ring-inset ring-gray-200">
<div class="flex justify-between gap-x-4">
<div class="py-0.5 text-xs leading-5 text-gray-500">
<span class="font-medium text-gray-900">{{
comment.person.name
}}</span>
commented
</div>

<time
:datetime="comment.dateTime"
class="flex-none py-0.5 text-xs leading-5 text-gray-500"
>{{ comment.date }}</time
>
</div>

<p class="text-sm leading-6 text-gray-500">
{{ comment.comment }}
</p>
</div>
</li>
</ul>

<div v-else class="mt-6 text-sm leading-5 text-gray-500">No comments yet</div>

<AddCommentForm :project-uid="$props.projectUid" />
</template>
104 changes: 103 additions & 1 deletion src/views/Project.vue
Original file line number Diff line number Diff line change
@@ -1 +1,103 @@
<template>Welcome to {{ $route.params.id }}</template>
<script setup lang="ts">
import { computed } from "vue";
import { useRoute } from "vue-router";
import { useProjectStore } from "@/projects";
import Comments from "./Comments.vue";
const store = useProjectStore();
const route = useRoute();
const project = computed(() =>
store.projects.find((project) => project.projectId === route.params.id),
);
</script>

<template>
<div class="px-4 py-5 sm:px-6">
<h1 class="text-3xl font-bold tracking-tight text-gray-900">
{{ project?.title }}
</h1>

<p class="mt-1 text-sm text-gray-500">
{{ project?.description }}
</p>
</div>

<div class="border-b border-gray-100">
<dl class="divide-y divide-gray-100">
<!-- About Section -->
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-gray-900">About</dt>

<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{{ project?.textContent }}
</dd>
</div>

<!-- Links Section -->
<div
v-if="project?.links && project.links.length > 0"
class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
>
<dt class="text-sm font-medium leading-6 text-gray-900">Links</dt>

<dd class="mt-2 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
<ul
role="list"
class="divide-y divide-gray-100 rounded-md border border-gray-200"
>
<li
v-for="link in project?.links"
:key="link"
class="flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6"
>
{{ link }}
</li>
</ul>
</dd>
</div>

<!-- Tags Section -->
<div
v-if="project?.tags && project.tags.length > 0"
class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
>
<dt class="text-sm font-medium leading-6 text-gray-900">Tags</dt>

<dd class="mt-2 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
<ul role="list" class="flex space-x-2">
<li
v-for="tag in project?.tags"
:key="tag"
class="rounded-md bg-blue-200 px-2 py-1 text-sm leading-6 text-blue-800"
>
{{ tag }}
</li>
</ul>
</dd>
</div>

<!-- Upvotes Section -->
<div
v-if="project?.upvotes && project.upvotes.length > 0"
class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
>
<dt class="text-sm font-medium leading-6 text-gray-900">Upvotes</dt>

<dd class="mt-2 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
{{ project?.upvotes.length }} people upvoted this project.
</dd>
</div>

<!-- Any Other Sections You Want to Add -->
</dl>
</div>

<div class="mt-10 px-4 py-6 sm:px-6">
<h2 class="text-xl font-semibold leading-6 text-gray-900">Comments</h2>

<Comments v-if="project?._id" :project-uid="project._id" />
</div>
</template>
12 changes: 4 additions & 8 deletions src/views/ProjectCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,21 @@ const props = defineProps<{
project: Project;
}>();
const firstImage = computed(() => {
const images = props.project.images;
return images[0];
});
const href = computed(() => `/projects/${props.project.projectId}`);
</script>

<template>
<li class="project">
<router-link as="li" :to="href" class="flex min-w-0 gap-x-4">
<img
v-if="firstImage"
v-if="project.logo"
class="h-12 w-12 flex-none rounded-full bg-gray-50"
:src="firstImage"
:src="project.logo"
alt=""
/>

<div v-else class="h-12 w-12 flex-none" />

<div class="flex h-full min-w-0 flex-auto flex-col">
<div>
<p class="text-md font-semibold leading-6 text-gray-900">
Expand Down

0 comments on commit 5b040f7

Please sign in to comment.