mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-04 20:55:19 +02:00
commit
aec34a617f
24 changed files with 437 additions and 323 deletions
|
@ -9,7 +9,4 @@ services:
|
|||
- ORIGIN=http://localhost:3000
|
||||
- SKIP_DB_WAIT=true
|
||||
# Only necessary for externaly hosted databases such as NeonDB
|
||||
volumes:
|
||||
- ./sql:/sql
|
||||
|
||||
# docker compose -f ./compose-dev.yml up --build
|
||||
# docker compose -f ./compose-dev.yml up --build
|
||||
|
|
|
@ -11,8 +11,6 @@ services:
|
|||
# Only necessary for externaly hosted databases such as NeonDB
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
- ./sql:/sql
|
||||
db:
|
||||
image: postgres
|
||||
environment:
|
||||
|
|
|
@ -4,38 +4,31 @@
|
|||
import calendar from "$lib/assets/calendar.svg";
|
||||
import { goto } from "$app/navigation";
|
||||
import { desc } from "drizzle-orm";
|
||||
import type { Adventure } from "$lib/utils/types";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let type: String;
|
||||
|
||||
export let name: String | undefined = undefined;
|
||||
export let location: String | undefined = undefined;
|
||||
export let date: String | undefined = undefined;
|
||||
export let id: Number | undefined = undefined;
|
||||
export let regionId: String | undefined = undefined;
|
||||
export let visited: Boolean | undefined = undefined;
|
||||
export let countryCode: String | undefined = undefined;
|
||||
export let adventure: Adventure;
|
||||
|
||||
// export let name: String | undefined = undefined;
|
||||
// export let location: String | undefined = undefined;
|
||||
// export let date: String | undefined = undefined;
|
||||
// export let id: Number | undefined = undefined;
|
||||
|
||||
function remove() {
|
||||
dispatch("remove", id);
|
||||
dispatch("remove", adventure.id);
|
||||
}
|
||||
function edit() {
|
||||
dispatch("edit", id);
|
||||
dispatch("edit", adventure.id);
|
||||
}
|
||||
function add() {
|
||||
dispatch("add", { name, location });
|
||||
}
|
||||
function markVisited() {
|
||||
dispatch("markVisited", regionId);
|
||||
visited = true;
|
||||
}
|
||||
function removeVisit() {
|
||||
dispatch("removeVisit", regionId);
|
||||
visited = false;
|
||||
dispatch("add", adventure);
|
||||
}
|
||||
|
||||
function moreInfo() {
|
||||
goto(`/worldtravel/${countryCode}/${regionId}`);
|
||||
console.log(adventure.id);
|
||||
goto(`/adventure/${adventure.id}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -43,26 +36,39 @@
|
|||
class="card min-w-max lg:w-96 md:w-80 sm:w-60 xs:w-40 bg-primary-content shadow-xl overflow-hidden text-base-content"
|
||||
>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title overflow-ellipsis">{name}</h2>
|
||||
{#if location && location !== ""}
|
||||
<h2 class="card-title overflow-ellipsis">{adventure.name}</h2>
|
||||
{#if adventure.location && adventure.location !== ""}
|
||||
<div class="inline-flex items-center">
|
||||
<iconify-icon icon="mdi:map-marker" class="text-xl"></iconify-icon>
|
||||
<p class="ml-.5">{location}</p>
|
||||
<p class="ml-.5">{adventure.location}</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if date && date !== ""}
|
||||
{#if adventure.date && adventure.date !== ""}
|
||||
<div class="inline-flex items-center">
|
||||
<iconify-icon icon="mdi:calendar" class="text-xl"></iconify-icon>
|
||||
<p class="ml-1">{date}</p>
|
||||
<p class="ml-1">{adventure.date}</p>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="card-actions justify-end">
|
||||
{#if type == "mylog"}
|
||||
<button class="btn btn-primary" on:click={edit}>Edit</button>
|
||||
<button class="btn btn-secondary" on:click={remove}>Remove</button>
|
||||
<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}>Add</button>
|
||||
<button class="btn btn-primary" on:click={add}
|
||||
><iconify-icon icon="mdi:plus" class="text-2xl"
|
||||
></iconify-icon></button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
<script lang="ts">
|
||||
export let editId: number = NaN;
|
||||
export let editName: string = "";
|
||||
export let editLocation: string = "";
|
||||
export let editdate: string = "";
|
||||
export let adventureToEdit: Adventure;
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import type { Adventure } from "$lib/utils/types";
|
||||
const dispatch = createEventDispatcher();
|
||||
import { onMount } from "svelte";
|
||||
let modal: HTMLDialogElement;
|
||||
|
||||
let originalName = editName;
|
||||
let originalName = adventureToEdit.name;
|
||||
|
||||
onMount(() => {
|
||||
modal = document.getElementById("my_modal_1") as HTMLDialogElement;
|
||||
|
@ -19,14 +16,8 @@
|
|||
});
|
||||
|
||||
function submit() {
|
||||
const adventureEdited: Adventure = {
|
||||
id: editId,
|
||||
name: editName,
|
||||
location: editLocation,
|
||||
date: editdate,
|
||||
};
|
||||
dispatch("submit", adventureEdited);
|
||||
console.log(adventureEdited);
|
||||
dispatch("submit", adventureToEdit);
|
||||
console.log(adventureToEdit);
|
||||
}
|
||||
|
||||
function close() {
|
||||
|
@ -56,7 +47,7 @@
|
|||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
bind:value={editName}
|
||||
bind:value={adventureToEdit.name}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
|
@ -65,16 +56,25 @@
|
|||
<input
|
||||
type="text"
|
||||
id="location"
|
||||
bind:value={editLocation}
|
||||
bind:value={adventureToEdit.location}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date">date</label>
|
||||
<label for="date">Date</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
bind:value={editdate}
|
||||
bind:value={adventureToEdit.date}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date">Description</label>
|
||||
<input
|
||||
type="text"
|
||||
id="description"
|
||||
bind:value={adventureToEdit.description}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
|
|
95
src/lib/components/MoreFieldsInput.svelte
Normal file
95
src/lib/components/MoreFieldsInput.svelte
Normal file
|
@ -0,0 +1,95 @@
|
|||
<script lang="ts">
|
||||
let newAdventure: Adventure;
|
||||
|
||||
newAdventure = {
|
||||
id: -1,
|
||||
type: "mylog",
|
||||
name: "",
|
||||
location: "",
|
||||
date: "",
|
||||
};
|
||||
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import type { Adventure } from "$lib/utils/types";
|
||||
const dispatch = createEventDispatcher();
|
||||
import { onMount } from "svelte";
|
||||
let modal: HTMLDialogElement;
|
||||
|
||||
onMount(() => {
|
||||
modal = document.getElementById("my_modal_1") as HTMLDialogElement;
|
||||
if (modal) {
|
||||
modal.showModal();
|
||||
}
|
||||
});
|
||||
|
||||
function create() {
|
||||
dispatch("create", newAdventure);
|
||||
console.log(newAdventure);
|
||||
}
|
||||
|
||||
function close() {
|
||||
dispatch("close");
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Escape") {
|
||||
close();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<dialog id="my_modal_1" class="modal">
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<div class="modal-box" role="dialog" on:keydown={handleKeydown} tabindex="0">
|
||||
<h3 class="font-bold text-lg">New Adventure</h3>
|
||||
<p class="py-4">Press ESC key or click the button below to close</p>
|
||||
<div
|
||||
class="modal-action items-center"
|
||||
style="display: flex; flex-direction: column; align-items: center; width: 100%;"
|
||||
>
|
||||
<form method="dialog" style="width: 100%;">
|
||||
<div>
|
||||
<label for="name">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
bind:value={newAdventure.name}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="location">Location</label>
|
||||
<input
|
||||
type="text"
|
||||
id="location"
|
||||
bind:value={newAdventure.location}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date">date</label>
|
||||
<input
|
||||
type="date"
|
||||
id="date"
|
||||
bind:value={newAdventure.date}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="date">Description</label>
|
||||
<input
|
||||
type="text"
|
||||
id="description"
|
||||
bind:value={newAdventure.description}
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
</div>
|
||||
<button class="btn btn-primary mr-4 mt-4" on:click={create}>Save</button
|
||||
>
|
||||
<!-- if there is a button in form, it will close the modal -->
|
||||
<button class="btn mt-4" on:click={close}>Close</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
|
@ -78,6 +78,10 @@
|
|||
<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
|
||||
> -->
|
||||
{/if}
|
||||
<button
|
||||
class="btn btn-primary my-2 md:my-0 md:mr-4"
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
<div class="card w-96 shadow-xl bg-primary-content">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">{user.first_name} {user.last_name}</h2>
|
||||
<p>{user.username} - {user.icon}</p>
|
||||
<p>
|
||||
{user.username}{#if user.icon}
|
||||
- {user.icon}{/if}
|
||||
</p>
|
||||
<p>Last Login: {user.last_login}</p>
|
||||
<p>date: {user.signup_date}</p>
|
||||
<p>{user.role}</p>
|
||||
|
|
|
@ -1,192 +1,56 @@
|
|||
{
|
||||
"quotes": [
|
||||
{
|
||||
"quote": "Believe you can and you're halfway there.",
|
||||
"author": "Theodore Roosevelt"
|
||||
},
|
||||
{
|
||||
"quote": "The only way to do great work is to love what you do.",
|
||||
"author": "Steve Jobs"
|
||||
},
|
||||
{
|
||||
"quote": "In the middle of every difficulty lies opportunity.",
|
||||
"author": "Albert Einstein"
|
||||
},
|
||||
{
|
||||
"quote": "The future belongs to those who believe in the beauty of their dreams.",
|
||||
"author": "Eleanor Roosevelt"
|
||||
},
|
||||
{
|
||||
"quote": "It does not matter how slowly you go as long as you do not stop.",
|
||||
"author": "Confucius"
|
||||
},
|
||||
{
|
||||
"quote": "Success is not final, failure is not fatal: It is the courage to continue that counts.",
|
||||
"author": "Winston Churchill"
|
||||
},
|
||||
{
|
||||
"quote": "The only limit to our realization of tomorrow will be our doubts of today.",
|
||||
"author": "Franklin D. Roosevelt"
|
||||
},
|
||||
{
|
||||
"quote": "Don't watch the clock; do what it does. Keep going.",
|
||||
"author": "Sam Levenson"
|
||||
},
|
||||
{
|
||||
"quote": "You are never too old to set another goal or to dream a new dream.",
|
||||
"author": "C.S. Lewis"
|
||||
},
|
||||
{
|
||||
"quote": "The only person you are destined to become is the person you decide to be.",
|
||||
"author": "Ralph Waldo Emerson"
|
||||
},
|
||||
{
|
||||
"quote": "Happiness is not something ready-made. It comes from your own actions.",
|
||||
"author": "Dalai Lama"
|
||||
},
|
||||
{
|
||||
"quote": "Life is what happens when you're busy making other plans.",
|
||||
"author": "John Lennon"
|
||||
},
|
||||
{
|
||||
"quote": "You miss 100% of the shots you don't take.",
|
||||
"author": "Wayne Gretzky"
|
||||
},
|
||||
{
|
||||
"quote": "The best time to plant a tree was 20 years ago. The second best time is now.",
|
||||
"author": "Chinese Proverb"
|
||||
},
|
||||
{
|
||||
"quote": "The only way to achieve the impossible is to believe it is possible.",
|
||||
"author": "Charles Kingsleigh"
|
||||
},
|
||||
{
|
||||
"quote": "Don't count the days, make the days count.",
|
||||
"author": "Muhammad Ali"
|
||||
},
|
||||
{
|
||||
"quote": "You don't have to be great to start, but you have to start to be great.",
|
||||
"author": "Zig Ziglar"
|
||||
},
|
||||
{
|
||||
"quote": "You can't go back and change the beginning, but you can start where you are and change the ending.",
|
||||
"author": "C.S. Lewis"
|
||||
},
|
||||
{
|
||||
"quote": "Dream big and dare to fail.",
|
||||
"author": "Norman Vaughan"
|
||||
},
|
||||
{
|
||||
"quote": "The secret of getting ahead is getting started.",
|
||||
"author": "Mark Twain"
|
||||
},
|
||||
{
|
||||
"quote": "Everything you can imagine is real.",
|
||||
"author": "Pablo Picasso"
|
||||
},
|
||||
{
|
||||
"quote": "You must be the change you wish to see in the world.",
|
||||
"author": "Mahatma Gandhi"
|
||||
},
|
||||
{
|
||||
"quote": "If you want to lift yourself up, lift up someone else.",
|
||||
"author": "Booker T. Washington"
|
||||
},
|
||||
{
|
||||
"quote": "Believe in yourself and all that you are. Know that there is something inside you that is greater than any obstacle.",
|
||||
"author": "Christian D. Larson"
|
||||
},
|
||||
{
|
||||
"quote": "The journey of a thousand miles begins with one step.",
|
||||
"author": "Lao Tzu"
|
||||
},
|
||||
{
|
||||
"quote": "Life isn't about waiting for the storm to pass, it's about learning to dance in the rain.",
|
||||
"author": "Vivian Greene"
|
||||
},
|
||||
{
|
||||
"quote": "You are never too old to set another goal or to dream a new dream.",
|
||||
"author": "Les Brown"
|
||||
},
|
||||
{
|
||||
"quote": "Your time is limited, don't waste it living someone else's life.",
|
||||
"author": "Steve Jobs"
|
||||
},
|
||||
{
|
||||
"quote": "Don't let yesterday take up too much of today.",
|
||||
"author": "Will Rogers"
|
||||
},
|
||||
{
|
||||
"quote": "The only thing standing between you and your goal is the story you keep telling yourself as to why you can't achieve it.",
|
||||
"author": "Jordan Belfort"
|
||||
},
|
||||
{
|
||||
"quote": "The future belongs to those who prepare for it today.",
|
||||
"author": "Malcolm X"
|
||||
},
|
||||
{
|
||||
"quote": "The greatest glory in living lies not in never falling, but in rising every time we fall.",
|
||||
"author": "Nelson Mandela"
|
||||
},
|
||||
{
|
||||
"quote": "It's not what happens to you, but how you react to it that matters.",
|
||||
"author": "Epictetus"
|
||||
},
|
||||
{
|
||||
"quote": "When one door of happiness closes, another opens, but often we look so long at the closed door that we do not see the one that has been opened for us.",
|
||||
"author": "Helen Keller"
|
||||
},
|
||||
{
|
||||
"quote": "The only thing that stands between you and your dream is the will to try and the belief that it is actually possible.",
|
||||
"author": "Joel Brown"
|
||||
},
|
||||
{
|
||||
"quote": "Success is walking from failure to failure with no loss of enthusiasm.",
|
||||
"author": "Winston Churchill"
|
||||
},
|
||||
{
|
||||
"quote": "Believe in yourself! Have faith in your abilities! Without a humble but reasonable confidence in your own powers you cannot be successful or happy.",
|
||||
"author": "Norman Vincent Peale"
|
||||
},
|
||||
{
|
||||
"quote": "The greatest adventure is what lies ahead.",
|
||||
"author": "J.R.R. Tolkien"
|
||||
},
|
||||
{
|
||||
"quote": "What you get by achieving your goals is not as important as what you become by achieving your goals.",
|
||||
"author": "Zig Ziglar"
|
||||
},
|
||||
{
|
||||
"quote": "To be yourself in a world that is constantly trying to make you something else is the greatest accomplishment.",
|
||||
"author": "Ralph Waldo Emerson"
|
||||
},
|
||||
{
|
||||
"quote": "What lies behind us and what lies before us are tiny matters compared to what lies within us.",
|
||||
"author": "Ralph Waldo Emerson"
|
||||
},
|
||||
{
|
||||
"quote": "The best and most beautiful things in the world cannot be seen or even touched - they must be felt with the heart.",
|
||||
"author": "Helen Keller"
|
||||
},
|
||||
{
|
||||
"quote": "I can't change the direction of the wind, but I can adjust my sails to always reach my destination.",
|
||||
"author": "Jimmy Dean"
|
||||
},
|
||||
{
|
||||
"quote": "If you're going through hell, keep going.",
|
||||
"author": "Winston Churchill"
|
||||
},
|
||||
{
|
||||
"quote": "Nothing is impossible, the word itself says 'I'm possible'!",
|
||||
"author": "Audrey Hepburn"
|
||||
},
|
||||
{
|
||||
"quote": "Keep your face always toward the sunshine - and shadows will fall behind you.",
|
||||
"author": "Walt Whitman"
|
||||
},
|
||||
{
|
||||
"quote": "Success is not the key to happiness. Happiness is the key to success. If you love what you are doing, you will be successful.",
|
||||
"author": "Albert Schweitzer"
|
||||
}
|
||||
]
|
||||
"quotes": [
|
||||
{
|
||||
"quote": "A journey of a thousand miles begins with a single step.",
|
||||
"author": "Lao Tzu"
|
||||
},
|
||||
{
|
||||
"quote": "If we were meant to stay in one place, we’d have roots instead of feet.",
|
||||
"author": "Rachel Wolchin"
|
||||
},
|
||||
{
|
||||
"quote": "Adventure isn’t hanging on a rope off the side of a mountain. Adventure is an attitude that we must apply to the day to day obstacles in life.",
|
||||
"author": "John Amatt"
|
||||
},
|
||||
{
|
||||
"quote": "Wherever you go, go with all your heart.",
|
||||
"author": "Confucius"
|
||||
},
|
||||
{
|
||||
"quote": "Until you step into the unknown, you don’t know what you’re made of.",
|
||||
"author": "Roy T. Bennett"
|
||||
},
|
||||
{
|
||||
"quote": "You can’t control the past, but you can control where you go next.",
|
||||
"author": "Kirsten Hubbard"
|
||||
},
|
||||
{
|
||||
"quote": "Life isn’t about finding yourself. Life is about creating yourself.",
|
||||
"author": "George Bernard Shaw"
|
||||
},
|
||||
{
|
||||
"quote": "It is not the mountain we conquer, but ourselves.",
|
||||
"author": "Edmund Hillary"
|
||||
},
|
||||
{
|
||||
"quote": "I am not the same, having seen the moon shine on the other side of the world.",
|
||||
"author": "Mary Anne Radmacher"
|
||||
},
|
||||
{
|
||||
"quote": "A mind that is stretched by a new experience can never go back to its old dimensions.",
|
||||
"author": "Oliver Wendell Holmes"
|
||||
},
|
||||
{
|
||||
"quote": "Life is short and the world is wide.",
|
||||
"author": "Simon Raven"
|
||||
},
|
||||
{
|
||||
"quote": "Only those who risk going too far can possibly find out how far they can go.",
|
||||
"author": "T.S. Eliot"
|
||||
},
|
||||
{
|
||||
"quote": "Believe you can and you're halfway there.",
|
||||
"author": "Theodore Roosevelt"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import type { LayoutServerLoad, PageServerLoad } from "./$types";
|
||||
let USING_VERCEL: string;
|
||||
|
||||
try {
|
||||
USING_VERCEL = require("$env/static/private").USING_VERCEL;
|
||||
} catch (error) {}
|
||||
const env = await import("$env/static/private");
|
||||
USING_VERCEL = env.USING_VERCEL;
|
||||
} catch (error) {
|
||||
USING_VERCEL = "false";
|
||||
}
|
||||
|
||||
export const load: LayoutServerLoad = async (event) => {
|
||||
if (event.locals.user) {
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
if (data.usingVercel === "true") {
|
||||
inject();
|
||||
injectSpeedInsights();
|
||||
} else {
|
||||
// console.log("Not using Vercel");
|
||||
}
|
||||
|
||||
let isServerSetup = data.isServerSetup;
|
||||
|
|
|
@ -35,9 +35,17 @@ export const actions: Actions = {
|
|||
// change the theme only if it is one of the allowed themes
|
||||
if (
|
||||
theme &&
|
||||
["light", "dark", "night", "retro", "forest", "aqua", "forest"].includes(
|
||||
theme
|
||||
)
|
||||
[
|
||||
"light",
|
||||
"dark",
|
||||
"night",
|
||||
"retro",
|
||||
"forest",
|
||||
"aqua",
|
||||
"forest",
|
||||
"garden",
|
||||
"emerald",
|
||||
].includes(theme)
|
||||
) {
|
||||
cookies.set("colortheme", theme, {
|
||||
path: "/",
|
||||
|
|
32
src/routes/adventure/[id]/+page.server.ts
Normal file
32
src/routes/adventure/[id]/+page.server.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { redirect } from "@sveltejs/kit";
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { db } from "$lib/db/db.server";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { adventureTable } from "$lib/db/schema";
|
||||
|
||||
export const load = (async (event) => {
|
||||
if (!event.locals.user) {
|
||||
return redirect(302, "/login");
|
||||
}
|
||||
|
||||
let adventureUserId = await db
|
||||
.select({ userId: adventureTable.userId })
|
||||
.from(adventureTable)
|
||||
.where(eq(adventureTable.id, Number(event.params.id)))
|
||||
.limit(1)
|
||||
.execute();
|
||||
|
||||
console.log(adventureUserId);
|
||||
|
||||
if (
|
||||
adventureUserId &&
|
||||
adventureUserId[0]?.userId !== event.locals.user.id &&
|
||||
adventureUserId !== null
|
||||
) {
|
||||
return redirect(302, "/log");
|
||||
}
|
||||
|
||||
let adventure = await event.fetch(`/api/adventure?id=${event.params.id}`);
|
||||
|
||||
return { adventure: await adventure.json() };
|
||||
}) satisfies PageServerLoad;
|
66
src/routes/adventure/[id]/+page.svelte
Normal file
66
src/routes/adventure/[id]/+page.svelte
Normal file
|
@ -0,0 +1,66 @@
|
|||
<script lang="ts">
|
||||
import type { Adventure } from "$lib/utils/types";
|
||||
import { onMount } from "svelte";
|
||||
import type { PageData } from "./$types";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
let adventure: Adventure;
|
||||
|
||||
onMount(() => {
|
||||
if (data.adventure.adventure) {
|
||||
adventure = data.adventure.adventure[0];
|
||||
} else {
|
||||
goto("/404");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if !adventure}
|
||||
<div class="flex justify-center items-center w-full mt-16">
|
||||
<span class="loading loading-spinner w-24 h-24"></span>
|
||||
</div>
|
||||
{:else}
|
||||
{#if adventure.name}
|
||||
<h1 class="text-center font-extrabold text-4xl mb-2">{adventure.name}</h1>
|
||||
{/if}
|
||||
{#if adventure.location}
|
||||
<p class="text-center text-2xl">
|
||||
<iconify-icon icon="mdi:map-marker" class="text-xl -mb-0.5"
|
||||
></iconify-icon>{adventure.location}
|
||||
</p>
|
||||
{/if}
|
||||
{#if adventure.date}
|
||||
<p class="text-center text-lg mt-4 pl-16 pr-16">
|
||||
Visited on: {adventure.date}
|
||||
</p>
|
||||
{/if}
|
||||
{#if adventure.rating !== undefined && adventure.rating !== null}
|
||||
<div class="flex justify-center items-center">
|
||||
<div class="rating" aria-readonly="true">
|
||||
{#each Array.from({ length: 5 }, (_, i) => i + 1) as star}
|
||||
<input
|
||||
type="radio"
|
||||
name="rating-1"
|
||||
class="mask mask-star"
|
||||
checked={star <= adventure.rating}
|
||||
disabled
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if adventure.description}
|
||||
<p class="text-center text-lg mt-4 pl-16 pr-16">{adventure.description}</p>
|
||||
{/if}
|
||||
{#if adventure.imageUrl}
|
||||
<div class="flex content-center justify-center">
|
||||
<img
|
||||
src={adventure.imageUrl}
|
||||
alt={adventure.name}
|
||||
class="w-50 mt-4 align-middle rounded-lg shadow-lg"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
45
src/routes/api/adventure/+server.ts
Normal file
45
src/routes/api/adventure/+server.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import { db } from "$lib/db/db.server";
|
||||
import { adventureTable } from "$lib/db/schema";
|
||||
import { json, type RequestEvent, type RequestHandler } from "@sveltejs/kit";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
/**
|
||||
* Handles the GET request for retrieving an adventure by ID.
|
||||
* @param {Request} request - The request object.
|
||||
* @param {Response} response - The response object.
|
||||
* @returns {Promise<void>} - A promise that resolves when the request is handled.
|
||||
*/
|
||||
export const GET: RequestHandler = async ({ url, locals }) => {
|
||||
const id = url.searchParams.get("id");
|
||||
const user = locals.user;
|
||||
|
||||
if (!user) {
|
||||
return json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!id) {
|
||||
return json({ error: "Missing adventure ID" }, { status: 400 });
|
||||
}
|
||||
|
||||
const adventure = await db
|
||||
.select()
|
||||
.from(adventureTable)
|
||||
.where(
|
||||
and(
|
||||
eq(adventureTable.id, Number(id)), // Convert id to number
|
||||
eq(adventureTable.userId, user.id),
|
||||
eq(adventureTable.type, "mylog")
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
.execute();
|
||||
|
||||
if (adventure.length === 0) {
|
||||
return json({ error: "Adventure not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
// console.log("GET /api/adventure?id=", id);
|
||||
// console.log("User:", user);
|
||||
|
||||
return json({ adventure }, { status: 200 });
|
||||
};
|
|
@ -86,7 +86,7 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
|
||||
const { newAdventure } = await event.request.json();
|
||||
console.log(newAdventure);
|
||||
const { name, location, date } = newAdventure;
|
||||
const { name, location, date, description } = newAdventure;
|
||||
|
||||
// insert the adventure to the user's visited list
|
||||
await db
|
||||
|
@ -97,6 +97,7 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
name: name,
|
||||
location: location,
|
||||
date: date,
|
||||
description: description,
|
||||
})
|
||||
.execute();
|
||||
let res = await db
|
||||
|
@ -107,7 +108,8 @@ export async function POST(event: RequestEvent): Promise<Response> {
|
|||
eq(adventureTable.userId, event.locals.user.id),
|
||||
eq(adventureTable.name, name),
|
||||
eq(adventureTable.location, location),
|
||||
eq(adventureTable.date, date)
|
||||
eq(adventureTable.date, date),
|
||||
eq(adventureTable.description, description)
|
||||
)
|
||||
)
|
||||
.execute();
|
||||
|
@ -142,7 +144,7 @@ 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 } = newAdventure;
|
||||
const { name, location, date, id, description } = newAdventure;
|
||||
|
||||
// update the adventure in the user's visited list
|
||||
await db
|
||||
|
@ -151,6 +153,7 @@ export async function PUT(event: RequestEvent): Promise<Response> {
|
|||
name: name,
|
||||
location: location,
|
||||
date: date,
|
||||
description: description,
|
||||
})
|
||||
.where(
|
||||
and(
|
||||
|
@ -162,7 +165,7 @@ export async function PUT(event: RequestEvent): Promise<Response> {
|
|||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
adventure: { id, name, location, date },
|
||||
adventure: { id, name, location, date, description },
|
||||
message: { message: "Adventure updated" },
|
||||
}),
|
||||
{
|
||||
|
|
|
@ -10,11 +10,10 @@
|
|||
count = value;
|
||||
});
|
||||
|
||||
async function add(event: CustomEvent<{ name: string; location: string }>) {
|
||||
async function add(event: CustomEvent<Adventure>) {
|
||||
let newAdventure: Adventure = {
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: "",
|
||||
type: "mylog",
|
||||
id: -1,
|
||||
};
|
||||
|
@ -47,14 +46,7 @@
|
|||
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 data.result as adventure (adventure.id)}
|
||||
<AdventureCard
|
||||
type="featured"
|
||||
on:add={add}
|
||||
name={adventure.name}
|
||||
location={adventure.location}
|
||||
date=""
|
||||
id={NaN}
|
||||
/>
|
||||
<AdventureCard type="featured" on:add={add} {adventure} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
import EditModal from "$lib/components/EditModal.svelte";
|
||||
import { generateRandomString } from "$lib";
|
||||
import { visitCount } from "$lib/utils/stores/visitCountStore";
|
||||
import MoreFieldsInput from "$lib/components/MoreFieldsInput.svelte";
|
||||
|
||||
let newName = "";
|
||||
let newLocation = "";
|
||||
|
||||
let editId: number = NaN;
|
||||
let editName: string = "";
|
||||
let editLocation: string = "";
|
||||
let editdate: string = "";
|
||||
let isShowingMoreFields = false;
|
||||
|
||||
let adventureToEdit: Adventure | undefined;
|
||||
|
||||
let isShowingToast: boolean = false;
|
||||
let toastAction: string = "";
|
||||
|
@ -59,16 +59,13 @@
|
|||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
const createNewAdventure = () => {
|
||||
let currentDate = new Date();
|
||||
let dateString = currentDate.toISOString().slice(0, 10); // Get date in "yyyy-mm-dd" format
|
||||
// post to /api/visits
|
||||
|
||||
const createNewAdventure = (event: { detail: Adventure }) => {
|
||||
let newAdventure: Adventure = {
|
||||
type: "mylog",
|
||||
name: newName,
|
||||
location: newLocation,
|
||||
date: dateString,
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: event.detail.date,
|
||||
description: event.detail.description,
|
||||
id: -1,
|
||||
};
|
||||
|
||||
|
@ -90,9 +87,10 @@
|
|||
{
|
||||
id: newId,
|
||||
type: "mylog",
|
||||
name: newName,
|
||||
location: newLocation,
|
||||
date: dateString,
|
||||
name: event.detail.name,
|
||||
location: event.detail.location,
|
||||
date: event.detail.date,
|
||||
description: event.detail.description,
|
||||
},
|
||||
];
|
||||
newName = ""; // Reset newName and newLocation after adding adventure
|
||||
|
@ -114,6 +112,7 @@
|
|||
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
|
||||
|
@ -133,10 +132,7 @@
|
|||
adventures = adventures.map((adventure) =>
|
||||
adventure.id === event.detail.id ? event.detail : adventure
|
||||
);
|
||||
editId = NaN;
|
||||
editName = "";
|
||||
editLocation = "";
|
||||
editdate = "";
|
||||
adventureToEdit = undefined;
|
||||
showToast("Adventure edited successfully!");
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -149,10 +145,7 @@
|
|||
(adventure) => adventure.id === event.detail
|
||||
);
|
||||
if (adventure) {
|
||||
editId = adventure.id || 0;
|
||||
editName = adventure.name || "";
|
||||
editLocation = adventure.location || "";
|
||||
editdate = adventure.date || "";
|
||||
adventureToEdit = adventure;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,10 +172,8 @@
|
|||
}
|
||||
|
||||
function handleClose() {
|
||||
editId = NaN;
|
||||
editName = "";
|
||||
editLocation = "";
|
||||
editdate = "";
|
||||
adventureToEdit = undefined;
|
||||
isShowingMoreFields = false;
|
||||
}
|
||||
|
||||
function deleteData() {
|
||||
|
@ -238,21 +229,13 @@
|
|||
</div>
|
||||
|
||||
<div class="flex flex-row items-center justify-center gap-4">
|
||||
<form on:submit={createNewAdventure} class="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={newName}
|
||||
placeholder="Adventure Name"
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={newLocation}
|
||||
placeholder="Adventure Location"
|
||||
class="input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<input class="btn btn-primary" type="submit" value="Add Adventure" />
|
||||
</form>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
on:click={() => (isShowingMoreFields = !isShowingMoreFields)}
|
||||
>
|
||||
Show More Fields
|
||||
</button>
|
||||
</div>
|
||||
{#if adventures.length != 0}
|
||||
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||
|
@ -272,12 +255,17 @@
|
|||
<SucessToast action={toastAction} />
|
||||
{/if}
|
||||
|
||||
{#if !Number.isNaN(editId)}
|
||||
{#if isShowingMoreFields}
|
||||
<MoreFieldsInput
|
||||
on:create={createNewAdventure}
|
||||
on:close={handleClose}
|
||||
on:submit={saveAdventure}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if adventureToEdit && adventureToEdit.id != undefined}
|
||||
<EditModal
|
||||
bind:editId
|
||||
bind:editName
|
||||
bind:editLocation
|
||||
bind:editdate
|
||||
bind:adventureToEdit
|
||||
on:submit={saveAdventure}
|
||||
on:close={handleClose}
|
||||
/>
|
||||
|
@ -288,11 +276,8 @@
|
|||
>
|
||||
{#each adventures as adventure (adventure.id)}
|
||||
<AdventureCard
|
||||
{adventure}
|
||||
type="mylog"
|
||||
id={adventure.id}
|
||||
name={adventure.name}
|
||||
location={adventure.location}
|
||||
date={adventure.date}
|
||||
on:edit={editAdventure}
|
||||
on:remove={removeAdventure}
|
||||
/>
|
||||
|
|
0
src/routes/planner/+page.server.ts
Normal file
0
src/routes/planner/+page.server.ts
Normal file
1
src/routes/planner/+page.svelte
Normal file
1
src/routes/planner/+page.svelte
Normal file
|
@ -0,0 +1 @@
|
|||
<h1>Welcome to the planner</h1>
|
|
@ -8,7 +8,7 @@ import {
|
|||
userVisitedWorldTravel,
|
||||
} from "$lib/db/schema";
|
||||
import type { DatabaseUser } from "$lib/server/auth";
|
||||
import { count } from "drizzle-orm";
|
||||
import { count, eq } from "drizzle-orm";
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
let users: DatabaseUser[] = [];
|
||||
|
@ -26,6 +26,7 @@ export const load: PageServerLoad = async (event) => {
|
|||
visitCount = (await db
|
||||
.select({ count: count() })
|
||||
.from(adventureTable)
|
||||
.where(eq(adventureTable.type, "mylog"))
|
||||
.execute()) as unknown as number;
|
||||
userCount = (await db
|
||||
.select({ count: count() })
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
import { enhance } from "$app/forms";
|
||||
|
||||
let loading = false;
|
||||
|
||||
function toggleLoad() {
|
||||
loading = !loading;
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1 class="text-center font-bold text-4xl">AdventureLog Setup</h1>
|
||||
|
@ -16,7 +20,7 @@
|
|||
<h2 class="text-center font-bold text-2xl mt-6">Create Admin User</h2>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<form method="post" use:enhance class="w-full max-w-xs">
|
||||
<form method="post" use:enhance={toggleLoad} class="w-full max-w-xs">
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
name="username"
|
||||
|
@ -59,4 +63,4 @@
|
|||
name="description"
|
||||
content="Setup AdventureLog with your admin account"
|
||||
/>
|
||||
</svelte:head>;
|
||||
</svelte:head>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import type { Adventure } from "$lib/utils/types";
|
||||
export let data;
|
||||
let array = data.adventureArray as Adventure[];
|
||||
console.log(array);
|
||||
import AdventureCard from "$lib/components/AdventureCard.svelte";
|
||||
</script>
|
||||
|
||||
|
@ -20,13 +21,7 @@
|
|||
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 array as adventure (adventure.id)}
|
||||
<AdventureCard
|
||||
type="shared"
|
||||
id={adventure.id}
|
||||
name={adventure.name}
|
||||
location={adventure.location}
|
||||
date={adventure.date}
|
||||
/>
|
||||
<AdventureCard type="shared" {adventure} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -61,4 +61,4 @@
|
|||
name="description"
|
||||
content="Signup for AdventureLog to start logging your adventures!"
|
||||
/>
|
||||
</svelte:head>;
|
||||
</svelte:head>
|
||||
|
|
|
@ -6,6 +6,15 @@ export default {
|
|||
},
|
||||
plugins: [require("@tailwindcss/typography"), require("daisyui")],
|
||||
daisyui: {
|
||||
themes: ["light", "dark", "night", "retro", "forest", "aqua", "garden"],
|
||||
themes: [
|
||||
"light",
|
||||
"dark",
|
||||
"night",
|
||||
"retro",
|
||||
"forest",
|
||||
"aqua",
|
||||
"garden",
|
||||
"emerald",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue