1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-08-01 19:25:17 +02:00

feat: Add "Planner" button to Navbar component

The code changes include adding a "Planner" button to the Navbar component. This button allows users to navigate to the Planner page. The changes involve modifying the Navbar component in the src/lib/components/Navbar.svelte file.
This commit is contained in:
Sean Morley 2024-05-04 15:00:02 +00:00
parent 3127784632
commit 716323657b
6 changed files with 424 additions and 2 deletions

View file

@ -76,6 +76,20 @@
></iconify-icon></button
>
{/if}
{#if type == "planner"}
<button class="btn btn-primary" on:click={moreInfo}
><iconify-icon icon="mdi:launch" class="text-2xl"
></iconify-icon></button
>
<button class="btn btn-primary" on:click={edit}
><iconify-icon icon="mdi:file-document-edit" class="text-2xl"
></iconify-icon></button
>
<button class="btn btn-secondary" on:click={remove}
><iconify-icon icon="mdi:trash-can-outline" class="text-2xl"
></iconify-icon></button
>
{/if}
{#if type == "featured"}
<button class="btn btn-primary" on:click={add}
><iconify-icon icon="mdi:plus" class="text-2xl"

View file

@ -78,6 +78,11 @@
<button class="btn btn-primary my-2 md:my-0 md:mr-4" on:click={goToLog}
>My Log</button
>
<button
class="btn btn-primary my-2 md:my-0 md:mr-4"
on:click={() => goto("/planner")}>Planner</button
>
<!-- <button
class="btn btn-primary my-2 md:my-0 md:mr-4"
on:click={() => goto("/planner")}>Planner</button

View file

@ -0,0 +1,223 @@
import { lucia } from "$lib/server/auth";
import { error, type RequestEvent } from "@sveltejs/kit";
import { adventureTable } from "$lib/db/schema";
import { db } from "$lib/db/db.server";
import { and, eq } from "drizzle-orm";
import type { Adventure } from "$lib/utils/types";
// Gets all the adventures that the user has visited
export async function GET(event: RequestEvent): Promise<Response> {
if (!event.locals.user) {
return new Response(JSON.stringify({ error: "No user found" }), {
status: 401,
headers: {
"Content-Type": "application/json",
},
});
}
let result = await db
.select()
.from(adventureTable)
.where(
and(
eq(adventureTable.userId, event.locals.user.id),
eq(adventureTable.type, "planner")
)
)
.execute();
return new Response(
// turn the result into an Adventure object array
JSON.stringify(
result.map((r) => {
const adventure: Adventure = r as Adventure;
if (typeof adventure.activityTypes === "string") {
try {
adventure.activityTypes = JSON.parse(adventure.activityTypes);
} catch (error) {
console.error("Error parsing activityTypes:", error);
adventure.activityTypes = undefined;
}
}
return adventure;
})
),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}
// deletes the adventure given the adventure id and the user object
export async function DELETE(event: RequestEvent): Promise<Response> {
if (!event.locals.user) {
return new Response(JSON.stringify({ error: "No user found" }), {
status: 401,
headers: {
"Content-Type": "application/json",
},
});
}
// get id from the body
const { id } = await event.request.json();
if (!id) {
return new Response(JSON.stringify({ error: "No id found" }), {
status: 400,
headers: {
"Content-Type": "application/json",
},
});
}
let res = await db
.delete(adventureTable)
.where(
and(
eq(adventureTable.userId, event.locals.user.id),
eq(adventureTable.id, Number(id))
)
)
.execute();
return new Response(JSON.stringify({ id: id, res: res }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}
export async function POST(event: RequestEvent): Promise<Response> {
if (!event.locals.user) {
return new Response(JSON.stringify({ error: "No user found" }), {
status: 401,
headers: {
"Content-Type": "application/json",
},
});
}
const body = await event.request.json();
if (!body.detailAdventure) {
return error(400, {
message: "No adventure data provided",
});
}
const { name, location, date, description, activityTypes, rating } =
body.detailAdventure;
if (!name) {
return error(400, {
message: "Name field is required!",
});
}
if (rating && (rating < 1 || rating > 5)) {
return error(400, {
message: "Rating must be between 1 and 5",
});
}
console.log(activityTypes);
// insert the adventure to the user's visited list
let res = await db
.insert(adventureTable)
.values({
userId: event.locals.user.id,
type: "planner",
name: name,
location: location || null,
date: date || null,
description: description || null,
activityTypes: JSON.stringify(activityTypes) || null,
rating: rating || null,
})
.returning({ insertedId: adventureTable.id })
.execute();
let insertedId = res[0].insertedId;
console.log(insertedId);
body.detailAdventure.id = insertedId;
// return a response with the adventure object values
return new Response(
JSON.stringify({
adventure: body.detailAdventure,
message: { message: "Adventure added" },
id: insertedId,
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}
// put route to update existing adventure
export async function PUT(event: RequestEvent): Promise<Response> {
if (!event.locals.user) {
return new Response(JSON.stringify({ error: "No user found" }), {
status: 401,
headers: {
"Content-Type": "application/json",
},
});
}
const body = await event.request.json();
if (!body.detailAdventure) {
return error(400, {
message: "No adventure data provided",
});
}
const { name, location, date, description, activityTypes, id, rating } =
body.detailAdventure;
if (!name) {
return error(400, {
message: "Name field is required!",
});
}
// update the adventure in the user's visited list
await db
.update(adventureTable)
.set({
name: name,
location: location,
date: date,
description: description,
rating: rating,
activityTypes: JSON.stringify(activityTypes),
})
.where(
and(
eq(adventureTable.userId, event.locals.user.id),
eq(adventureTable.id, Number(id))
)
)
.execute();
return new Response(
JSON.stringify({
adventure: body.detailAdventure,
message: { message: "Adventure updated" },
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}

View file

@ -18,7 +18,12 @@ export async function GET(event: RequestEvent): Promise<Response> {
let result = await db
.select()
.from(adventureTable)
.where(eq(adventureTable.userId, event.locals.user.id))
.where(
and(
eq(adventureTable.userId, event.locals.user.id),
eq(adventureTable.type, "mylog")
)
)
.execute();
return new Response(
// turn the result into an Adventure object array

View file

@ -0,0 +1,14 @@
import { redirect } from "@sveltejs/kit";
import type { PageServerLoad } from "./$types";
import type { Adventure } from "$lib/utils/types";
export const load: PageServerLoad = async (event) => {
if (!event.locals.user) {
return redirect(302, "/login");
}
const response = await event.fetch("/api/planner");
const result = await response.json();
return {
result,
};
};

View file

@ -1 +1,162 @@
<h1>Welcome to the planner</h1>
<script lang="ts">
import type { Adventure } from "$lib/utils/types.js";
import { onMount } from "svelte";
import AdventureCard from "$lib/components/AdventureCard.svelte";
import EditModal from "$lib/components/EditModal.svelte";
import MoreFieldsInput from "$lib/components/CreateNewAdventure.svelte";
export let data;
let plans: Adventure[] = [];
let isLoading = true;
onMount(async () => {
console.log(data);
plans = data.result;
isLoading = false;
});
let isShowingMoreFields: boolean = false;
let adventureToEdit: Adventure | undefined;
console.log(data);
function editPlan(event: { detail: number }) {
const adventure = plans.find((adventure) => adventure.id === event.detail);
if (adventure) {
adventureToEdit = adventure;
}
}
function handleClose() {
adventureToEdit = undefined;
isShowingMoreFields = false;
}
function savePlan(event: { detail: Adventure }) {
console.log("Event", event.detail);
let detailAdventure = event.detail;
// put request to /api/visits with id and adventure data
fetch("/api/planner", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
detailAdventure,
}),
})
.then((response) => response.json())
.then((data) => {
console.log("Success:", data);
// update local array with new data
const index = plans.findIndex(
(adventure) => adventure.id === detailAdventure.id
);
if (index !== -1) {
plans[index] = detailAdventure;
}
adventureToEdit = undefined;
// showToast("Adventure edited successfully!");
})
.catch((error) => {
console.error("Error:", error);
});
}
function removeAdventure(event: { detail: number }) {
console.log("Event ID " + event.detail);
// send delete request to server at /api/visits
fetch("/api/visits", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: event.detail }),
})
.then((response) => response.json())
.then((data) => {
console.log("Success:", data);
// remove adventure from array where id matches
plans = plans.filter((adventure) => adventure.id !== event.detail);
// showToast("Adventure removed successfully!");
// visitCount.update((n) => n - 1);
})
.catch((error) => {
console.error("Error:", error);
});
}
const createNewAdventure = (event: { detail: Adventure }) => {
isShowingMoreFields = false;
let detailAdventure = event.detail;
console.log("Event" + event.detail.name);
fetch("/api/planner", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
detailAdventure,
}),
})
.then((response) => {
if (!response.ok) {
return response.json().then((data) => {
throw new Error(
data.error || `Failed to add adventure - ${data?.message}`
);
});
}
return response.json();
})
.then((data) => {
// add to local array for instant view update
plans = [...plans, data.adventure];
// showToast("Adventure added successfully!");
// visitCount.update((n) => n + 1);
})
.catch((error) => {
console.error("Error:", error);
// showToast(error.message);
});
};
</script>
<div class="flex flex-row items-center justify-center gap-4">
<button
type="button"
class="btn btn-secondary"
on:click={() => (isShowingMoreFields = !isShowingMoreFields)}
>
<iconify-icon icon="mdi:plus" class="text-2xl"></iconify-icon>
</button>
</div>
{#if isLoading}
<div class="flex justify-center items-center w-full mt-16">
<span class="loading loading-spinner w-24 h-24"></span>
</div>
{/if}
<div
class="grid xl:grid-cols-3 lg:grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-4 mt-4 content-center auto-cols-auto ml-6 mr-6"
>
{#each plans as adventure (adventure.id)}
<AdventureCard
{adventure}
type="planner"
on:edit={editPlan}
on:remove={removeAdventure}
/>
{/each}
</div>
{#if adventureToEdit && adventureToEdit.id != undefined}
<EditModal bind:adventureToEdit on:submit={savePlan} on:close={handleClose} />
{/if}
{#if isShowingMoreFields}
<MoreFieldsInput on:create={createNewAdventure} on:close={handleClose} />
{/if}