Add geographic coordinates to Transportation model and update related components
This commit is contained in:
@@ -12,8 +12,6 @@
|
||||
import NotFound from '$lib/components/NotFound.svelte';
|
||||
import { DefaultMarker, MapLibre, Popup } from 'svelte-maplibre';
|
||||
import TransportationCard from '$lib/components/TransportationCard.svelte';
|
||||
import EditTransportation from '$lib/components/EditTransportation.svelte';
|
||||
import NewTransportation from '$lib/components/NewTransportation.svelte';
|
||||
import NoteCard from '$lib/components/NoteCard.svelte';
|
||||
import NoteModal from '$lib/components/NoteModal.svelte';
|
||||
|
||||
@@ -26,6 +24,7 @@
|
||||
import ChecklistCard from '$lib/components/ChecklistCard.svelte';
|
||||
import ChecklistModal from '$lib/components/ChecklistModal.svelte';
|
||||
import AdventureModal from '$lib/components/AdventureModal.svelte';
|
||||
import TransportationModal from '$lib/components/TransportationModal.svelte';
|
||||
|
||||
export let data: PageData;
|
||||
console.log(data);
|
||||
@@ -108,9 +107,8 @@
|
||||
}
|
||||
|
||||
let adventureToEdit: Adventure | null = null;
|
||||
let transportationToEdit: Transportation;
|
||||
let transportationToEdit: Transportation | null = null;
|
||||
let isAdventureModalOpen: boolean = false;
|
||||
let isTransportationEditModalOpen: boolean = false;
|
||||
let isNoteModalOpen: boolean = false;
|
||||
let noteToEdit: Note | null;
|
||||
let checklistToEdit: Checklist | null;
|
||||
@@ -122,17 +120,12 @@
|
||||
isAdventureModalOpen = true;
|
||||
}
|
||||
|
||||
function saveNewTransportation(event: CustomEvent<Transportation>) {
|
||||
transportations = transportations.map((transportation) => {
|
||||
if (transportation.id === event.detail.id) {
|
||||
return event.detail;
|
||||
}
|
||||
return transportation;
|
||||
});
|
||||
isTransportationEditModalOpen = false;
|
||||
function editTransportation(event: CustomEvent<Transportation>) {
|
||||
transportationToEdit = event.detail;
|
||||
isShowingTransportationModal = true;
|
||||
}
|
||||
|
||||
function saveOrCreate(event: CustomEvent<Adventure>) {
|
||||
function saveOrCreateAdventure(event: CustomEvent<Adventure>) {
|
||||
if (adventures.find((adventure) => adventure.id === event.detail.id)) {
|
||||
adventures = adventures.map((adventure) => {
|
||||
if (adventure.id === event.detail.id) {
|
||||
@@ -145,6 +138,22 @@
|
||||
}
|
||||
isAdventureModalOpen = false;
|
||||
}
|
||||
|
||||
function saveOrCreateTransportation(event: CustomEvent<Transportation>) {
|
||||
if (transportations.find((transportation) => transportation.id === event.detail.id)) {
|
||||
// Update existing transportation
|
||||
transportations = transportations.map((transportation) => {
|
||||
if (transportation.id === event.detail.id) {
|
||||
return event.detail;
|
||||
}
|
||||
return transportation;
|
||||
});
|
||||
} else {
|
||||
// Create new transportation
|
||||
transportations = [event.detail, ...transportations];
|
||||
}
|
||||
isShowingTransportationModal = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isShowingLinkModal}
|
||||
@@ -157,13 +166,12 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if isTransportationEditModalOpen}
|
||||
<EditTransportation
|
||||
{#if isShowingTransportationModal}
|
||||
<TransportationModal
|
||||
{transportationToEdit}
|
||||
on:close={() => (isTransportationEditModalOpen = false)}
|
||||
on:saveEdit={saveNewTransportation}
|
||||
startDate={collection.start_date}
|
||||
endDate={collection.end_date}
|
||||
on:close={() => (isShowingTransportationModal = false)}
|
||||
on:save={saveOrCreateTransportation}
|
||||
{collection}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -171,7 +179,7 @@
|
||||
<AdventureModal
|
||||
{adventureToEdit}
|
||||
on:close={() => (isAdventureModalOpen = false)}
|
||||
on:save={saveOrCreate}
|
||||
on:save={saveOrCreateAdventure}
|
||||
{collection}
|
||||
/>
|
||||
{/if}
|
||||
@@ -221,19 +229,6 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if isShowingTransportationModal}
|
||||
<NewTransportation
|
||||
on:close={() => (isShowingTransportationModal = false)}
|
||||
on:add={(event) => {
|
||||
transportations = [event.detail, ...transportations];
|
||||
isShowingTransportationModal = false;
|
||||
}}
|
||||
{collection}
|
||||
startDate={collection.start_date}
|
||||
endDate={collection.end_date}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if notFound}
|
||||
<div
|
||||
class="flex min-h-[100dvh] flex-col items-center justify-center bg-background px-4 py-12 sm:px-6 lg:px-8 -mt-20"
|
||||
@@ -300,6 +295,8 @@
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
on:click={() => {
|
||||
// Reset the transportation object for creating a new one
|
||||
transportationToEdit = null;
|
||||
isShowingTransportationModal = true;
|
||||
newType = '';
|
||||
}}
|
||||
@@ -415,10 +412,7 @@
|
||||
on:delete={(event) => {
|
||||
transportations = transportations.filter((t) => t.id != event.detail);
|
||||
}}
|
||||
on:edit={(event) => {
|
||||
transportationToEdit = event.detail;
|
||||
isTransportationEditModalOpen = true;
|
||||
}}
|
||||
on:edit={editTransportation}
|
||||
{collection}
|
||||
/>
|
||||
{/each}
|
||||
@@ -534,7 +528,7 @@
|
||||
}}
|
||||
on:edit={(event) => {
|
||||
transportationToEdit = event.detail;
|
||||
isTransportationEditModalOpen = true;
|
||||
isShowingTransportationModal = true;
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { t } from 'svelte-i18n';
|
||||
import TotpModal from '$lib/components/TOTPModal.svelte';
|
||||
import { appTitle, appVersion } from '$lib/config.js';
|
||||
|
||||
export let data;
|
||||
let user: User;
|
||||
@@ -154,195 +155,220 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<h1 class="text-center font-extrabold text-4xl mb-6">{$t('settings.settings_page')}</h1>
|
||||
|
||||
<h1 class="text-center font-extrabold text-xl">{$t('settings.account_settings')}</h1>
|
||||
<div class="flex justify-center">
|
||||
<form
|
||||
method="post"
|
||||
action="?/changeDetails"
|
||||
use:enhance
|
||||
class="w-full max-w-xs"
|
||||
enctype="multipart/form-data"
|
||||
>
|
||||
<label for="username">{$t('auth.username')}</label>
|
||||
<input
|
||||
bind:value={user.username}
|
||||
name="username"
|
||||
id="username"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<label for="first_name">{$t('auth.first_name')}</label>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={user.first_name}
|
||||
name="first_name"
|
||||
id="first_name"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
|
||||
<label for="last_name">{$t('auth.last_name')}</label>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={user.last_name}
|
||||
name="last_name"
|
||||
id="last_name"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/><br />
|
||||
<label for="profilePicture">{$t('auth.profile_picture')}</label>
|
||||
<input
|
||||
type="file"
|
||||
name="profile_pic"
|
||||
id="profile_pic"
|
||||
class="file-input file-input-bordered w-full max-w-xs mb-2"
|
||||
/><br />
|
||||
<div class="form-control">
|
||||
<div class="tooltip tooltip-info" data-tip={$t('auth.public_tooltip')}>
|
||||
<label class="label cursor-pointer">
|
||||
<span class="label-text">{$t('auth.public_profile')}</span>
|
||||
<div class="container mx-auto p-6 max-w-4xl">
|
||||
<h1 class="text-3xl font-extrabold text-center mb-6">
|
||||
{$t('settings.settings_page')}
|
||||
</h1>
|
||||
|
||||
<!-- Account Settings Section -->
|
||||
<section class="space-y-8">
|
||||
<h2 class="text-2xl font-semibold text-center">
|
||||
{$t('settings.account_settings')}
|
||||
</h2>
|
||||
<div class=" bg-neutral p-6 rounded-lg shadow-md">
|
||||
<form
|
||||
method="post"
|
||||
action="?/changeDetails"
|
||||
use:enhance
|
||||
enctype="multipart/form-data"
|
||||
class="space-y-6"
|
||||
>
|
||||
<div>
|
||||
<label for="username" class="text-sm font-medium">{$t('auth.username')}</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
bind:value={user.username}
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="first_name" class="text-sm font-medium">{$t('auth.first_name')}</label>
|
||||
<input
|
||||
type="text"
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
bind:value={user.first_name}
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last_name" class="text-sm font-medium">{$t('auth.last_name')}</label>
|
||||
<input
|
||||
type="text"
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
bind:value={user.last_name}
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="profile_pic" class="text-sm font-medium">{$t('auth.profile_picture')}</label>
|
||||
<input
|
||||
type="file"
|
||||
id="profile_pic"
|
||||
name="profile_pic"
|
||||
class="file-input file-input-bordered file-input-primary mt-1 w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="public_profile"
|
||||
name="public_profile"
|
||||
type="checkbox"
|
||||
class="toggle"
|
||||
checked={user.public_profile}
|
||||
bind:checked={user.public_profile}
|
||||
class="toggle toggle-primary"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<label for="public_profile" class="ml-2 text-sm">{$t('auth.public_profile')}</label>
|
||||
</div>
|
||||
|
||||
<button class="w-full mt-4 btn btn-primary py-2">{$t('settings.update')}</button>
|
||||
</form>
|
||||
</div>
|
||||
<button class="py-2 mt-2 px-4 btn btn-primary">{$t('settings.update')}</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{#if $page.form?.message}
|
||||
<div class="text-center text-error mt-4">
|
||||
{$t($page.form.message)}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.password_change')}</h1>
|
||||
<div class="flex justify-center">
|
||||
<form action="?/changePassword" method="post" class="w-full max-w-xs" use:enhance>
|
||||
<input
|
||||
type="password"
|
||||
name="current_password"
|
||||
placeholder={$t('settings.current_password')}
|
||||
id="current_password"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<br />
|
||||
<input
|
||||
type="password"
|
||||
name="password1"
|
||||
placeholder={$t('settings.new_password')}
|
||||
id="password1"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<br />
|
||||
<input
|
||||
type="password"
|
||||
name="password2"
|
||||
id="password2"
|
||||
placeholder={$t('settings.confirm_new_password')}
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<div class="tooltip tooltip-warning" data-tip={$t('settings.password_change_lopout_warning')}>
|
||||
<button class="py-2 px-4 btn btn-primary mt-2">{$t('settings.password_change')}</button>
|
||||
</div>
|
||||
<br />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.email_change')}</h1>
|
||||
|
||||
<div class="flex justify-center mb-4">
|
||||
<div>
|
||||
{#each emails as email}
|
||||
<p class="mb-2">
|
||||
{email.email}
|
||||
{#if email.verified}
|
||||
<div class="badge badge-success">{$t('settings.verified')}</div>
|
||||
{:else}
|
||||
<div class="badge badge-error">{$t('settings.not_verified')}</div>
|
||||
{/if}
|
||||
{#if email.primary}
|
||||
<div class="badge badge-primary">{$t('settings.primary')}</div>
|
||||
{/if}
|
||||
{#if !email.verified}
|
||||
<button class="btn btn-sm btn-secondary ml-2" on:click={() => verifyEmail(email)}
|
||||
>{$t('settings.verify')}</button
|
||||
<!-- Password Change Section -->
|
||||
<section class="space-y-8">
|
||||
<h2 class="text-2xl font-semibold text-center mt-8">
|
||||
{$t('settings.password_change')}
|
||||
</h2>
|
||||
<div class="bg-neutral p-6 rounded-lg shadow-md">
|
||||
<form method="post" action="?/changePassword" use:enhance class="space-y-6">
|
||||
<div>
|
||||
<label for="current_password" class="text-sm font-medium"
|
||||
>{$t('settings.current_password')}</label
|
||||
>
|
||||
{/if}
|
||||
{#if !email.primary}
|
||||
<button class="btn btn-sm btn-secondary ml-2" on:click={() => primaryEmail(email)}
|
||||
>{$t('settings.make_primary')}</button
|
||||
<input
|
||||
type="password"
|
||||
id="current_password"
|
||||
name="current_password"
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password1" class="text-sm font-medium">{$t('settings.new_password')}</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password1"
|
||||
name="password1"
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password2" class="text-sm font-medium"
|
||||
>{$t('settings.confirm_new_password')}</label
|
||||
>
|
||||
{/if}
|
||||
<button class="btn btn-sm btn-warning ml-2" on:click={() => removeEmail(email)}
|
||||
>{$t('adventures.remove')}</button
|
||||
<input
|
||||
type="password"
|
||||
id="password2"
|
||||
name="password2"
|
||||
class="block w-full mt-1 input input-bordered input-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="tooltip tooltip-warning"
|
||||
data-tip={$t('settings.password_change_lopout_warning')}
|
||||
>
|
||||
</p>
|
||||
{/each}
|
||||
{#if emails.length === 0}
|
||||
<p>{$t('settings.no_emai_set')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mt-4">
|
||||
<form class="w-full max-w-xs" on:submit={addEmail}>
|
||||
<div class="mb-4">
|
||||
<input
|
||||
type="email"
|
||||
name="new_email"
|
||||
placeholder={$t('settings.new_email')}
|
||||
bind:value={new_email}
|
||||
id="new_email"
|
||||
class="block mb-2 input input-bordered w-full max-w-xs"
|
||||
/>
|
||||
<button class="w-full btn btn-primary py-2 mt-4">{$t('settings.password_change')}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<button class="py-2 px-4 mb-4 btn btn-primary">{$t('settings.email_change')}</button>
|
||||
</section>
|
||||
|
||||
<!-- Email Change Section -->
|
||||
<section class="space-y-8">
|
||||
<h2 class="text-2xl font-semibold text-center mt-8">
|
||||
{$t('settings.email_change')}
|
||||
</h2>
|
||||
<div class="bg-neutral p-6 rounded-lg shadow-md">
|
||||
<div>
|
||||
{#each emails as email}
|
||||
<div class="flex items-center space-x-2 mb-2">
|
||||
<span>{email.email}</span>
|
||||
{#if email.verified}
|
||||
<div class="badge badge-success">{$t('settings.verified')}</div>
|
||||
{:else}
|
||||
<div class="badge badge-error">{$t('settings.not_verified')}</div>
|
||||
{/if}
|
||||
{#if email.primary}
|
||||
<div class="badge badge-primary">{$t('settings.primary')}</div>
|
||||
{/if}
|
||||
{#if !email.verified}
|
||||
<button class="btn btn-sm btn-secondary" on:click={() => verifyEmail(email)}
|
||||
>{$t('settings.verify')}</button
|
||||
>
|
||||
{/if}
|
||||
{#if !email.primary}
|
||||
<button class="btn btn-sm btn-secondary" on:click={() => primaryEmail(email)}
|
||||
>{$t('settings.make_primary')}</button
|
||||
>
|
||||
{/if}
|
||||
<button class="btn btn-sm btn-warning" on:click={() => removeEmail(email)}
|
||||
>{$t('adventures.remove')}</button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
{#if emails.length === 0}
|
||||
<p class="text-center">{$t('settings.no_email_set')}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<form class="mt-4" on:submit={addEmail}>
|
||||
<input
|
||||
type="email"
|
||||
id="new_email"
|
||||
name="new_email"
|
||||
bind:value={new_email}
|
||||
placeholder={$t('settings.new_email')}
|
||||
class="block w-full input input-bordered input-primary"
|
||||
/>
|
||||
<button class="w-full mt-4 btn btn-primary py-2">{$t('settings.email_change')}</button>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<!-- MFA Section -->
|
||||
<section class="space-y-8">
|
||||
<h2 class="text-2xl font-semibold text-center mt-8">
|
||||
{$t('settings.mfa_page_title')}
|
||||
</h2>
|
||||
<div class="bg-neutral p-6 rounded-lg shadow-md text-center">
|
||||
{#if !data.props.authenticators}
|
||||
<p>{$t('settings.mfa_not_enabled')}</p>
|
||||
<button class="btn btn-primary mt-4" on:click={() => (isMFAModalOpen = true)}
|
||||
>{$t('settings.enable_mfa')}</button
|
||||
>
|
||||
{:else}
|
||||
<button class="btn btn-warning mt-4" on:click={disableMfa}
|
||||
>{$t('settings.disable_mfa')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Visited Region Check Section -->
|
||||
<section class="text-center mt-8">
|
||||
<h2 class="text-2xl font-semibold">{$t('adventures.visited_region_check')}</h2>
|
||||
<p>{$t('adventures.visited_region_check_desc')}</p>
|
||||
<button class="btn btn-neutral mt-4" on:click={checkVisitedRegions}
|
||||
>{$t('adventures.update_visited_regions')}</button
|
||||
>
|
||||
</section>
|
||||
|
||||
<small class="text-center block mt-8">
|
||||
<b>For Debug Use:</b> UUID={user.uuid} | Staff user: {user.is_staff} | {appTitle}
|
||||
{appVersion}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">{$t('settings.mfa_page_title')}</h1>
|
||||
|
||||
<div class="flex justify-center mb-4">
|
||||
<div>
|
||||
{#if !data.props.authenticators}
|
||||
<p>{$t('settings.mfa_not_enabled')}</p>
|
||||
<button class="btn btn-primary mt-2" on:click={() => (isMFAModalOpen = true)}
|
||||
>{$t('settings.enable_mfa')}</button
|
||||
>
|
||||
{:else}
|
||||
<button class="btn btn-warning mt-2" on:click={disableMfa}
|
||||
>{$t('settings.disable_mfa')}</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center mt-4">
|
||||
<h1 class="text-center font-extrabold text-xl mt-4 mb-2">
|
||||
{$t('adventures.visited_region_check')}
|
||||
</h1>
|
||||
<p>
|
||||
{$t('adventures.visited_region_check_desc')}
|
||||
</p>
|
||||
<p>{$t('adventures.update_visited_regions_disclaimer')}</p>
|
||||
|
||||
<button class="btn btn-neutral mt-2 mb-2" on:click={checkVisitedRegions}
|
||||
>{$t('adventures.update_visited_regions')}</button
|
||||
>
|
||||
</div>
|
||||
|
||||
<small class="text-center"
|
||||
><b>For Debug Use:</b> UUID={user.uuid} | Staff user: {user.is_staff}</small
|
||||
>
|
||||
|
||||
<svelte:head>
|
||||
<title>User Settings | AdventureLog</title>
|
||||
<meta
|
||||
|
||||
Reference in New Issue
Block a user