Skip to content

Commit

Permalink
feat: updateSnippet composable and fix somes minors others things
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianBx committed Nov 22, 2023
1 parent 6562dab commit 12aaa6e
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/composables/__tests__/useFilter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const datasMock = [
visibility: true,
},
{
id: "1",
id: "2",
title: "Component 2",
description: "A Angular component",
code: "code 2",
Expand Down
18 changes: 3 additions & 15 deletions src/composables/useFilter.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
import { ref, Ref, computed } from "vue";

interface DataItem {
id: string;
title: string;
description: string;
code: string;
language: string;
tags: string;
authorId: string;
createdAt: string;
updatedAt: string;
visibility: boolean;
}
import { Snippet } from "../utils/types/snippet";

export const searchQuery = ref("");

export default function useFilter(data: Ref<DataItem[]>) {
export default function useFilter(data: Ref<Snippet[]>) {
const filteredSnippets = computed(() => {
if (!searchQuery.value) {
return data.value;
}
return data.value.filter((item: DataItem) => {
return data.value.filter((item: Snippet) => {
return (
item.tags.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
item.title.toLowerCase().includes(searchQuery.value.toLowerCase())
Expand Down
31 changes: 0 additions & 31 deletions src/composables/useGetSnippet.ts

This file was deleted.

56 changes: 56 additions & 0 deletions src/composables/useGetSnippets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// useSnippets.ts
import { ref, Ref } from "vue";
import { db } from "../services/firebase/firebase.config";
import { collection, doc, getDoc, getDocs } from "firebase/firestore";
import { Snippet } from "../utils/types/snippet";

export function useGetSnippets() {
const snippets: Ref<Snippet[]> = ref([]);
const snippet: Ref<Snippet | null> = ref(null);
const isLoading: Ref<boolean> = ref(false);
const error: Ref<string | null> = ref(null);

const fetchSnippets = async () => {
isLoading.value = true;
error.value = null;
try {
const querySnapshot = await getDocs(collection(db, "snippets"));
snippets.value = querySnapshot.docs.map((doc) => ({
...(doc.data() as Snippet),
id: doc.id,
}));
} catch (err) {
error.value = (err as Error).message ?? "Could not fetch the snippets.";
} finally {
isLoading.value = false;
}
};

const fetchSnippetById = async (id: string) => {
console.log(id);
isLoading.value = true;
error.value = null;
try {
const docRef = doc(db, "snippets", id);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
snippet.value = { ...(docSnap.data() as Snippet) };
} else {
throw new Error("Snippet not found");
}
} catch (err) {
error.value = (err as Error).message ?? "Could not fetch the snippet.";
} finally {
isLoading.value = false;
}
};

return {
snippets,
snippet,
fetchSnippets,
fetchSnippetById,
isLoading,
error,
};
}
39 changes: 39 additions & 0 deletions src/composables/useUpdateSnippet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ref } from "vue";
import { db } from "../services/firebase/firebase.config";
import { doc, updateDoc, serverTimestamp } from "firebase/firestore";
import { Snippet } from "../utils/types/snippet";

export function useUpdateSnippet() {
const error = ref<string | null>(null);
const isUpdating = ref(false);

const updateSnippet = async (snippetData: Snippet): Promise<void> => {
try {
isUpdating.value = true;
const snippetId = snippetData.id;
if (!snippetId) {
throw new Error("Snippet ID is missing.");
}

const fullSnippetData = {
...snippetData,
updatedAt: serverTimestamp(),
};

const snippetDocRef = doc(db, "snippets", snippetId);
await updateDoc(snippetDocRef, fullSnippetData);
error.value = null;
} catch (e) {
error.value =
e instanceof Error ? e.message : "Could not update the snippet.";
} finally {
isUpdating.value = false;
}
};

return {
error,
isUpdating,
updateSnippet,
};
}
9 changes: 7 additions & 2 deletions src/views/HomeView.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<script setup lang="ts">
import { onMounted } from "vue";
import CardSnippet from "../components/CardSnippet.vue";
import SearchBar from "../components/SearchBar.vue";
import LayoutSlot from "../components/LayoutSlot.vue";
import useFilter from "../composables/useFilter";
import { useGetSnippets } from "../composables/useGetSnippet.ts";
import { useGetSnippets } from "../composables/useGetSnippets.ts";
const { snippets, isLoading, error } = useGetSnippets();
const { snippets, fetchSnippets, isLoading, error } = useGetSnippets();
const { filteredSnippets } = useFilter(snippets);
onMounted(() => {
fetchSnippets();
});
</script>

<template>
Expand Down
6 changes: 3 additions & 3 deletions src/views/RegisterView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ const handleGitHubLogin = async () => {
<form class="space-y-6" action="#" method="POST">
<div>
<InputForText
v-model="formData.email"
label="Email address"
:data="formData.email"
required
@update:data="(value: string) => handleUpdateData(value, 'email')"
/>
</div>

<div>
<InputForText
v-model="formData.password"
label="Password"
type="password"
:data="formData.password"
required
@update:data="
(value: string) => handleUpdateData(value, 'password')
Expand All @@ -74,9 +74,9 @@ const handleGitHubLogin = async () => {
</div>
<div>
<InputForText
v-model="formData.confirmPassword"
label="Confirm password"
type="password"
:data="formData.confirmPassword"
required
@update:data="
(value: string) => handleUpdateData(value, 'confirmPassword')
Expand Down
110 changes: 108 additions & 2 deletions src/views/SnippetView.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,111 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, reactive } from "vue";
import InputForText from "../components/InputForText.vue";
import InputForRichText from "../components/InputForRichText.vue";
import { useAuthStore } from "../store/authStore";
import { useUpdateSnippet } from "../composables/useUpdateSnippet";
import { useGetSnippets } from "../composables/useGetSnippets";
import { useRouter } from "vue-router";
const authStore = useAuthStore();
const router = useRouter();
const date = new Date();
const id = router.currentRoute.value.params.id;
const { snippet, fetchSnippetById } = useGetSnippets();
const snippetData = reactive({
id: id as string,
title: "",
description: "",
code: "",
language: "",
tags: "",
createdAt: date.toISOString(),
updatedAt: date.toISOString(),
authorId: authStore.idToken,
visibility: true,
});
const fillSnippetData = () => {
if (snippet.value) {
snippetData.title = snippet.value.title;
snippetData.description = snippet.value.description;
snippetData.code = snippet.value.code;
snippetData.language = snippet.value.language;
snippetData.createdAt = snippet.value.createdAt;
snippetData.tags = snippet.value.tags;
}
};
const { updateSnippet } = useUpdateSnippet();
const handleSubmit = (event: Event) => {
event.preventDefault();
updateSnippet(snippetData);
router.push("/");
};
onMounted(async () => {
if (!authStore.isLoggedIn) {
router.push("/login");
}
await fetchSnippetById(id.toString());
fillSnippetData();
});
</script>

<template>
<div>SnippetView</div>
<div class="flex min-h-full sm:mt-20 flex-1 flex-col justify-center">
<div class="px-4 sm:px-0 sm:mx-auto sm:w-full sm:max-w-[720px]">
<div
class="bg-background px-6 py-12 sm:rounded-xl sm:px-12 shadow-neumorphic"
>
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h3
class="pb-11 text-center text-2xl font-bold leading-9 tracking-tight text-primary"
>
Snippet: {{ snippet?.title }}
</h3>
</div>
<form class="space-y-6">
<div>
<InputForText v-model="snippetData.title" label="Title" required />
</div>

<div>
<InputForText
v-model="snippetData.description"
label="Description"
/>
</div>
<div>
<InputForText v-model="snippetData.tags" label="Tag" required />
</div>
<div>
<InputForText
v-model="snippetData.language"
label="Language"
required
/>
</div>
<div>
<InputForRichText
v-model="snippetData.code"
label="Code"
required
/>
</div>
<div>
<button
type="submit"
class="flex w-full justify-center text-base rounded-md shadow-neumorphic hover:shadow-inner-neumorphic bg-button px-3 py-3 font-semibold leading-6 text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-secondary"
@click="handleSubmit"
>
Save
</button>
</div>
</form>
</div>
</div>
</div>
</template>

0 comments on commit 12aaa6e

Please sign in to comment.