mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-04 20:55:19 +02:00
commit
89e4899e43
15 changed files with 747 additions and 67 deletions
|
@ -20,6 +20,7 @@
|
|||
dispatch("remove", adventure.id);
|
||||
}
|
||||
function edit() {
|
||||
console.log(adventure.activityTypes);
|
||||
dispatch("edit", adventure.id);
|
||||
}
|
||||
function add() {
|
||||
|
@ -49,6 +50,17 @@
|
|||
<p class="ml-1">{adventure.date}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if adventure.activityTypes && adventure.activityTypes.length > 0}
|
||||
<ul class="flex flex-wrap">
|
||||
{#each adventure.activityTypes as activity}
|
||||
<div
|
||||
class="badge badge-primary mr-1 text-md font-semibold pb-2 pt-1 mb-1"
|
||||
>
|
||||
{activity}
|
||||
</div>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
<div class="card-actions justify-end">
|
||||
{#if type == "mylog"}
|
||||
<button class="btn btn-primary" on:click={moreInfo}
|
||||
|
@ -64,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"
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
<script lang="ts">
|
||||
let newAdventure: Adventure;
|
||||
export let type: string;
|
||||
|
||||
newAdventure = {
|
||||
id: -1,
|
||||
type: "mylog",
|
||||
type: type,
|
||||
name: "",
|
||||
location: "",
|
||||
date: "",
|
||||
activityTypes: [],
|
||||
};
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
@ -23,6 +25,7 @@
|
|||
});
|
||||
|
||||
function create() {
|
||||
addActivityType();
|
||||
dispatch("create", newAdventure);
|
||||
console.log(newAdventure);
|
||||
}
|
||||
|
@ -36,6 +39,19 @@
|
|||
close();
|
||||
}
|
||||
}
|
||||
|
||||
let activityInput: string = "";
|
||||
|
||||
function addActivityType() {
|
||||
if (activityInput.trim() !== "") {
|
||||
const activities = activityInput
|
||||
.split(" ")
|
||||
.filter((activity) => activity.trim() !== "");
|
||||
newAdventure.activityTypes = activities;
|
||||
activityInput = "";
|
||||
}
|
||||
console.log(newAdventure.activityTypes);
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog id="my_modal_1" class="modal">
|
||||
|
@ -85,8 +101,30 @@
|
|||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-primary mr-4 mt-4" on:click={create}
|
||||
>Create</button
|
||||
<div>
|
||||
<label for="date">Activity Types (Comma Seperated)</label>
|
||||
<input
|
||||
type="text"
|
||||
id="activityTypes"
|
||||
bind:value={activityInput}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="rating">Rating</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="5"
|
||||
id="rating"
|
||||
bind:value={newAdventure.rating}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary mr-4 mt-4"
|
||||
on:click={create}>Create</button
|
||||
>
|
||||
<!-- if there is a button in form, it will close the modal -->
|
||||
<button class="btn mt-4" on:click={close}>Close</button>
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
import { onMount } from "svelte";
|
||||
let modal: HTMLDialogElement;
|
||||
|
||||
console.log(adventureToEdit.id);
|
||||
|
||||
let originalName = adventureToEdit.name;
|
||||
|
||||
onMount(() => {
|
||||
|
@ -13,9 +15,11 @@
|
|||
if (modal) {
|
||||
modal.showModal();
|
||||
}
|
||||
activityInput = (adventureToEdit?.activityTypes || []).join(", ");
|
||||
});
|
||||
|
||||
function submit() {
|
||||
addActivityType();
|
||||
dispatch("submit", adventureToEdit);
|
||||
console.log(adventureToEdit);
|
||||
}
|
||||
|
@ -29,6 +33,19 @@
|
|||
close();
|
||||
}
|
||||
}
|
||||
|
||||
let activityInput: string = "";
|
||||
|
||||
function addActivityType() {
|
||||
if (activityInput.trim() !== "") {
|
||||
const activities = activityInput
|
||||
.split(",")
|
||||
.filter((activity) => activity.trim() !== "");
|
||||
adventureToEdit.activityTypes = activities;
|
||||
activityInput = "";
|
||||
}
|
||||
console.log(adventureToEdit.activityTypes);
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog id="my_modal_1" class="modal">
|
||||
|
@ -78,6 +95,26 @@
|
|||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date">Activity Types (Comma Seperated)</label>
|
||||
<input
|
||||
type="text"
|
||||
id="activityTypes"
|
||||
bind:value={activityInput}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="rating">Rating</label>
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="5"
|
||||
id="rating"
|
||||
bind:value={adventureToEdit.rating}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-primary mr-4 mt-4" on:click={submit}>Save</button
|
||||
>
|
||||
<!-- if there is a button in form, it will close the modal -->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@ export const load = (async (event) => {
|
|||
return redirect(302, "/login");
|
||||
}
|
||||
|
||||
let adventureUserId = await db
|
||||
let adventureUserId: any[] = await db
|
||||
.select({ userId: adventureTable.userId })
|
||||
.from(adventureTable)
|
||||
.where(eq(adventureTable.id, Number(event.params.id)))
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
onMount(() => {
|
||||
if (data.adventure.adventure) {
|
||||
adventure = data.adventure.adventure[0];
|
||||
console.log(adventure.activityTypes);
|
||||
} else {
|
||||
goto("/404");
|
||||
}
|
||||
|
@ -59,8 +60,22 @@
|
|||
<img
|
||||
src={adventure.imageUrl}
|
||||
alt={adventure.name}
|
||||
class="w-50 mt-4 align-middle rounded-lg shadow-lg"
|
||||
class="w-1/2 mt-4 align-middle rounded-lg shadow-lg"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if adventure.activityTypes && adventure.activityTypes.length > 0}
|
||||
<div class="flex justify-center items-center mt-4">
|
||||
<p class="text-center text-lg">Activities: </p>
|
||||
<ul class="flex flex-wrap">
|
||||
{#each adventure.activityTypes as activity}
|
||||
<div
|
||||
class="badge badge-primary mr-1 text-md font-semibold pb-2 pt-1 mb-1"
|
||||
>
|
||||
{activity}
|
||||
</div>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { db } from "$lib/db/db.server";
|
||||
import { adventureTable } from "$lib/db/schema";
|
||||
import type { Adventure } from "$lib/utils/types";
|
||||
import { json, type RequestEvent, type RequestHandler } from "@sveltejs/kit";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
|
@ -38,6 +39,20 @@ export const GET: RequestHandler = async ({ url, locals }) => {
|
|||
return json({ error: "Adventure not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
JSON.stringify(
|
||||
adventure.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;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// console.log("GET /api/adventure?id=", id);
|
||||
// console.log("User:", user);
|
||||
|
||||
|
|
223
src/routes/api/planner/+server.ts
Normal file
223
src/routes/api/planner/+server.ts
Normal 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",
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
|
@ -18,11 +18,29 @@ 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
|
||||
JSON.stringify(result.map((r) => r as Adventure)),
|
||||
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: {
|
||||
|
@ -73,7 +91,6 @@ export async function DELETE(event: RequestEvent): Promise<Response> {
|
|||
});
|
||||
}
|
||||
|
||||
// add the adventure to the user's visited list
|
||||
export async function POST(event: RequestEvent): Promise<Response> {
|
||||
if (!event.locals.user) {
|
||||
return new Response(JSON.stringify({ error: "No user found" }), {
|
||||
|
@ -84,9 +101,15 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
});
|
||||
}
|
||||
|
||||
const { newAdventure } = await event.request.json();
|
||||
console.log(newAdventure);
|
||||
const { name, location, date, description } = newAdventure;
|
||||
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, {
|
||||
|
@ -94,6 +117,14 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -104,6 +135,8 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
location: location || null,
|
||||
date: date || null,
|
||||
description: description || null,
|
||||
activityTypes: JSON.stringify(activityTypes) || null,
|
||||
rating: rating || null,
|
||||
})
|
||||
.returning({ insertedId: adventureTable.id })
|
||||
.execute();
|
||||
|
@ -111,10 +144,12 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
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: { name, location, date },
|
||||
adventure: body.detailAdventure,
|
||||
message: { message: "Adventure added" },
|
||||
id: insertedId,
|
||||
}),
|
||||
|
@ -138,10 +173,21 @@ export async function PUT(event: RequestEvent): Promise<Response> {
|
|||
});
|
||||
}
|
||||
|
||||
// get properties from the body
|
||||
const { newAdventure } = await event.request.json();
|
||||
console.log(newAdventure);
|
||||
const { name, location, date, id, description } = newAdventure;
|
||||
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
|
||||
|
@ -151,6 +197,8 @@ export async function PUT(event: RequestEvent): Promise<Response> {
|
|||
location: location,
|
||||
date: date,
|
||||
description: description,
|
||||
rating: rating,
|
||||
activityTypes: JSON.stringify(activityTypes),
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
|
@ -162,7 +210,7 @@ export async function PUT(event: RequestEvent): Promise<Response> {
|
|||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
adventure: { id, name, location, date, description },
|
||||
adventure: body.detailAdventure,
|
||||
message: { message: "Adventure updated" },
|
||||
}),
|
||||
{
|
||||
|
|
|
@ -11,12 +11,7 @@
|
|||
});
|
||||
|
||||
async function add(event: CustomEvent<Adventure>) {
|
||||
let newAdventure: Adventure = {
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
type: "mylog",
|
||||
id: -1,
|
||||
};
|
||||
let detailAdventure = event.detail;
|
||||
|
||||
const response = await fetch("/api/visits", {
|
||||
method: "POST",
|
||||
|
@ -24,7 +19,7 @@
|
|||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
newAdventure,
|
||||
detailAdventure,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ export const load: PageServerLoad = async (event) => {
|
|||
}
|
||||
const response = await event.fetch("/api/visits");
|
||||
const result = await response.json();
|
||||
// let array = result.adventures as Adventure[];
|
||||
return {
|
||||
result,
|
||||
};
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
import { visitCount } from "$lib/utils/stores/visitCountStore";
|
||||
import MoreFieldsInput from "$lib/components/CreateNewAdventure.svelte";
|
||||
|
||||
let newName = "";
|
||||
let newLocation = "";
|
||||
|
||||
let isShowingMoreFields = false;
|
||||
|
||||
let adventureToEdit: Adventure | undefined;
|
||||
|
@ -60,14 +57,9 @@
|
|||
}
|
||||
|
||||
const createNewAdventure = (event: { detail: Adventure }) => {
|
||||
let newAdventure: Adventure = {
|
||||
type: "mylog",
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: event.detail.date,
|
||||
description: event.detail.description,
|
||||
id: -1,
|
||||
};
|
||||
isShowingMoreFields = false;
|
||||
let detailAdventure = event.detail;
|
||||
console.log("Event" + event.detail.name);
|
||||
|
||||
fetch("/api/visits", {
|
||||
method: "POST",
|
||||
|
@ -75,7 +67,7 @@
|
|||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
newAdventure,
|
||||
detailAdventure,
|
||||
}),
|
||||
})
|
||||
.then((response) => {
|
||||
|
@ -89,21 +81,8 @@
|
|||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
let newId = data.id;
|
||||
// add to local array for instant view update
|
||||
adventures = [
|
||||
...adventures,
|
||||
{
|
||||
id: newId,
|
||||
type: "mylog",
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: event.detail.date,
|
||||
description: event.detail.description,
|
||||
},
|
||||
];
|
||||
newName = ""; // Reset newName and newLocation after adding adventure
|
||||
newLocation = "";
|
||||
adventures = [...adventures, data.adventure];
|
||||
showToast("Adventure added successfully!");
|
||||
visitCount.update((n) => n + 1);
|
||||
})
|
||||
|
@ -114,34 +93,29 @@
|
|||
};
|
||||
|
||||
function saveAdventure(event: { detail: Adventure }) {
|
||||
console.log("Event" + event.detail);
|
||||
console.log("Event", event.detail);
|
||||
let detailAdventure = event.detail;
|
||||
|
||||
let newAdventure: Adventure = {
|
||||
type: "mylog",
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: event.detail.date,
|
||||
id: event.detail.id,
|
||||
description: event.detail.description,
|
||||
};
|
||||
|
||||
// put request to /api/visits with id and advneture data
|
||||
// put request to /api/visits with id and adventure data
|
||||
fetch("/api/visits", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
newAdventure,
|
||||
detailAdventure,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log("Success:", data);
|
||||
// update local array with new data
|
||||
adventures = adventures.map((adventure) =>
|
||||
adventure.id === event.detail.id ? event.detail : adventure
|
||||
const index = adventures.findIndex(
|
||||
(adventure) => adventure.id === detailAdventure.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
adventures[index] = detailAdventure;
|
||||
}
|
||||
adventureToEdit = undefined;
|
||||
showToast("Adventure edited successfully!");
|
||||
})
|
||||
|
@ -161,6 +135,12 @@
|
|||
|
||||
function shareLink() {
|
||||
let key = generateRandomString();
|
||||
|
||||
// console log each adventure in the array
|
||||
for (let i = 0; i < adventures.length; i++) {
|
||||
console.log(adventures[i]);
|
||||
}
|
||||
|
||||
let data = JSON.stringify(adventures);
|
||||
fetch("/api/share", {
|
||||
method: "POST",
|
||||
|
@ -269,7 +249,7 @@
|
|||
<MoreFieldsInput
|
||||
on:create={createNewAdventure}
|
||||
on:close={handleClose}
|
||||
on:submit={saveAdventure}
|
||||
type="mylog"
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
};
|
|
@ -1 +1,179 @@
|
|||
<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";
|
||||
import {
|
||||
saveAdventure,
|
||||
removeAdventure,
|
||||
} from "../../services/adventureService.js";
|
||||
import SucessToast from "$lib/components/SucessToast.svelte";
|
||||
import mapDrawing from "$lib/assets/adventure_map.svg";
|
||||
export let data;
|
||||
let plans: Adventure[] = [];
|
||||
let isLoading = true;
|
||||
|
||||
onMount(async () => {
|
||||
console.log(data);
|
||||
plans = data.result;
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
let isShowingMoreFields: boolean = false;
|
||||
|
||||
let isShowingToast: boolean = false;
|
||||
let toastAction: string = "";
|
||||
|
||||
let adventureToEdit: Adventure | undefined;
|
||||
|
||||
console.log(data);
|
||||
|
||||
function showToast(action: string) {
|
||||
toastAction = action;
|
||||
isShowingToast = true;
|
||||
|
||||
setTimeout(() => {
|
||||
isShowingToast = false;
|
||||
toastAction = "";
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function editPlan(event: { detail: number }) {
|
||||
const adventure = plans.find((adventure) => adventure.id === event.detail);
|
||||
if (adventure) {
|
||||
adventureToEdit = adventure;
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
adventureToEdit = undefined;
|
||||
isShowingMoreFields = false;
|
||||
}
|
||||
|
||||
async function savePlan(event: { detail: Adventure }) {
|
||||
let newArray = await saveAdventure(event.detail, plans);
|
||||
if (newArray.length > 0) {
|
||||
plans = newArray;
|
||||
showToast("Adventure updated successfully!");
|
||||
} else {
|
||||
showToast("Failed to update adventure");
|
||||
}
|
||||
adventureToEdit = undefined;
|
||||
}
|
||||
|
||||
async function remove(event: { detail: number }) {
|
||||
let initialLength: number = plans.length;
|
||||
let theAdventure = plans.find((adventure) => adventure.id === event.detail);
|
||||
if (theAdventure) {
|
||||
let newArray = await removeAdventure(theAdventure, plans);
|
||||
if (newArray.length === initialLength - 1) {
|
||||
plans = newArray;
|
||||
showToast("Adventure removed successfully!");
|
||||
} else {
|
||||
showToast("Failed to remove adventure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
{#if isShowingToast}
|
||||
<SucessToast action={toastAction} />
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||
<article class="prose">
|
||||
<h2 class="text-center">Add new Plan</h2>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<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 plans.length != 0}
|
||||
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||
<article class="prose">
|
||||
<h1 class="text-center">My Adventure Plans</h1>
|
||||
</article>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#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={remove}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if plans.length == 0 && !isLoading}
|
||||
<div class="flex flex-col items-center justify-center mt-16">
|
||||
<article class="prose mb-4"><h2>Add some plans!</h2></article>
|
||||
<img src={mapDrawing} width="25%" alt="Logo" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if adventureToEdit && adventureToEdit.id != undefined}
|
||||
<EditModal bind:adventureToEdit on:submit={savePlan} on:close={handleClose} />
|
||||
{/if}
|
||||
|
||||
{#if isShowingMoreFields}
|
||||
<MoreFieldsInput
|
||||
on:create={createNewAdventure}
|
||||
on:close={handleClose}
|
||||
type="planner"
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
@ -1 +1,108 @@
|
|||
import type { Adventure } from "$lib/utils/types";
|
||||
|
||||
// json that maps the type to api routes
|
||||
const apiRoutes: { [key: string]: string } = {
|
||||
planner: "/api/planner",
|
||||
mylog: "/api/visits",
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves an adventure by sending a PUT request to the corresponding API endpoint.
|
||||
* If the request is successful, the local adventure array is updated with the new data.
|
||||
* If the request fails, an empty array is returned to allow for handling errors.
|
||||
* @param adventure - The adventure object to be saved.
|
||||
* @param adventureArray - The array of adventures to be updated.
|
||||
* @returns A promise that resolves to the updated adventure array.
|
||||
*/
|
||||
export async function saveAdventure(
|
||||
adventure: Adventure,
|
||||
adventureArray: Adventure[]
|
||||
): Promise<Adventure[]> {
|
||||
const detailAdventure = adventure;
|
||||
const type = detailAdventure.type;
|
||||
const url = apiRoutes[type];
|
||||
|
||||
// put request to /api/visits with id and adventure data
|
||||
const response = await fetch(url, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
detailAdventure,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// update local array with new data
|
||||
const index = adventureArray.findIndex(
|
||||
(adventure) => adventure.id === detailAdventure.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
adventureArray[index] = detailAdventure;
|
||||
}
|
||||
// showToast("Adventure edited successfully!");
|
||||
} else {
|
||||
console.error("Error:", response.statusText);
|
||||
adventureArray = [];
|
||||
}
|
||||
|
||||
return adventureArray;
|
||||
}
|
||||
|
||||
export async function removeAdventure(
|
||||
adventure: Adventure,
|
||||
adventureArray: Adventure[]
|
||||
): Promise<Adventure[]> {
|
||||
let url = apiRoutes[adventure.type];
|
||||
// delete request to /api/visits with id
|
||||
const response = await fetch(url, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ id: adventure.id }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
// remove adventure from array where id matches
|
||||
adventureArray = adventureArray.filter(
|
||||
(existingAdventure) => existingAdventure.id !== adventure.id
|
||||
);
|
||||
// showToast("Adventure removed successfully!");
|
||||
} else {
|
||||
console.error("Error:", response.statusText);
|
||||
adventureArray = [];
|
||||
}
|
||||
|
||||
console.log(adventureArray);
|
||||
|
||||
return adventureArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue