mirror of
https://github.com/vcscsvcscs/GenerationsHeritage.git
synced 2025-08-12 13:59:08 +02:00
upload media modal
This commit is contained in:
@@ -1,17 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { components } from '$lib/api/api.gen';
|
||||
import { video, photos, upload } from '$lib/paraglide/messages';
|
||||
import UploadMediaModal from '$lib/profile/editors/UploadMediaModal.svelte';
|
||||
|
||||
export let person: components['schemas']['PersonProperties'];
|
||||
export let editorMode = false;
|
||||
let uploadModal = false;
|
||||
let mediaType: 'audio' | 'video' | 'photo' | undefined = undefined;
|
||||
</script>
|
||||
|
||||
{#if editorMode}
|
||||
<button class="btn bg-neutral text-neutral-content btn-xs" on:click={() => {}}>
|
||||
{upload()}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if person.photos?.length || person.videos?.length}
|
||||
<div class="divider">{photos()} & {video()}</div>
|
||||
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
||||
@@ -30,3 +27,43 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if editorMode}
|
||||
<div class="divider">{upload()}</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<button
|
||||
class="btn btn-soft btn-xs"
|
||||
on:click={() => {
|
||||
uploadModal = true;
|
||||
mediaType = 'photo';
|
||||
}}
|
||||
>
|
||||
{'+ '+photos()}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-soft btn-xs"
|
||||
on:click={() => {
|
||||
uploadModal = true;
|
||||
mediaType = 'video';
|
||||
}}
|
||||
>
|
||||
{'+ '+video()}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if uploadModal}
|
||||
<UploadMediaModal
|
||||
closeModal={() => {
|
||||
uploadModal = false;
|
||||
}}
|
||||
{mediaType}
|
||||
onCreation={(newMedia: { url: string; name: string; description: string; date: string }) => {
|
||||
if (mediaType === 'photo') {
|
||||
person.photos = [...(person.photos ?? []), newMedia];
|
||||
} else if (mediaType === 'video') {
|
||||
person.videos = [...(person.videos ?? []), newMedia];
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { died } from './../paraglide/messages/en.js';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import ModalButtons from './ModalButtons.svelte';
|
||||
@@ -11,7 +12,12 @@
|
||||
let {
|
||||
closeModal = () => {},
|
||||
person = {}
|
||||
}: { closeModal: () => void; person: components['schemas']['PersonProperties'] } = $props();
|
||||
}: {
|
||||
closeModal: () => void;
|
||||
person: components['schemas']['PersonProperties'] & {
|
||||
id?: string;
|
||||
};
|
||||
} = $props();
|
||||
|
||||
let editorMode = $state(false);
|
||||
let draftPerson = $state({} as components['schemas']['PersonProperties']);
|
||||
@@ -22,7 +28,9 @@
|
||||
field: keyof components['schemas']['PersonProperties'],
|
||||
value: any
|
||||
) {
|
||||
console.log('Draft person change:', field, value);
|
||||
draftPerson[field] = value;
|
||||
console.log('Draft person:', draftPerson);
|
||||
}
|
||||
|
||||
function close() {
|
||||
@@ -35,20 +43,48 @@
|
||||
editorMode = !editorMode;
|
||||
}
|
||||
|
||||
function save() {
|
||||
// Save logic here
|
||||
async function save() {
|
||||
try {
|
||||
const response = await fetch(`/api/person/${person.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(draftPerson)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
alert('Error saving person data, status: ' + response.status);
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
person = { ...person, ...draftPerson };
|
||||
const data = (await response.json()) as {
|
||||
person?: components['schemas']['Person'];
|
||||
};
|
||||
console.log('Person data updated successfully:', draftPerson);
|
||||
console.log('Person data saved successfully:', data);
|
||||
return;
|
||||
} else {
|
||||
const errorDetails = await response.json();
|
||||
alert('Error saving person data, status: ' + response.status + ' ' + JSON.stringify(errorDetails));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('An unexpected error occurred: ' + error);
|
||||
}
|
||||
editorMode = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="modal modal-open" transition:fade>
|
||||
<div class="modal-box max-h-screen w-full max-w-5xl overflow-y-auto">
|
||||
<div class="bg-base-100 sticky top-0 z-10">
|
||||
<div class="bg-base-100 sticky top-0 z-7">
|
||||
<ModalButtons {editorMode} onClose={close} onSave={save} onToggleEdit={toggleEdit} />
|
||||
<div class="divider"></div>
|
||||
</div>
|
||||
<ProfileHeader {person} {editorMode} onChange={handleDraftPersonChange} />
|
||||
<MediaGallery {person} />
|
||||
<MediaGallery {person} {editorMode} />
|
||||
<LifeEventsTimeline
|
||||
person_life_events={person.life_events}
|
||||
{editorMode}
|
||||
|
101
apps/app/src/lib/profile/editors/UploadMediaModal.svelte
Normal file
101
apps/app/src/lib/profile/editors/UploadMediaModal.svelte
Normal file
@@ -0,0 +1,101 @@
|
||||
<script lang="ts">
|
||||
import { date, description, file, media_title, title, upload } from '$lib/paraglide/messages';
|
||||
|
||||
export let closeModal: () => void;
|
||||
export let onCreation:(newMedia:{
|
||||
url: string,
|
||||
name: string,
|
||||
description: string,
|
||||
date: string
|
||||
}) => void = () => {};
|
||||
export let mediaType: 'audio' | 'video' | 'photo' = 'photo';
|
||||
|
||||
let selectedFile: File | null = null;
|
||||
|
||||
let newMedia = {
|
||||
url: '',
|
||||
name: '',
|
||||
description: '',
|
||||
date: ''
|
||||
};
|
||||
|
||||
// Determine accepted input types based on mediaType
|
||||
$: acceptTypes =
|
||||
mediaType === 'audio' ? 'audio/*' : mediaType === 'video' ? 'video/*' : 'image/*';
|
||||
|
||||
function handleFileChange(e: Event) {
|
||||
const input = e.target as HTMLInputElement;
|
||||
if (input.files && input.files.length > 0) {
|
||||
selectedFile = input.files[0];
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadMedia() {
|
||||
if (!selectedFile) {
|
||||
alert('Please select a file');
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate file upload (replace with actual upload logic)
|
||||
newMedia.url = URL.createObjectURL(selectedFile);
|
||||
|
||||
// Emit event using custom dispatch
|
||||
const uploadEvent = new CustomEvent('upload', {
|
||||
detail: { ...newMedia }
|
||||
});
|
||||
dispatchEvent(uploadEvent);
|
||||
|
||||
// Clean up
|
||||
selectedFile = null;
|
||||
newMedia = { url: '', name: '', description: '', date: '' };
|
||||
onCreation(newMedia);
|
||||
closeModal();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="modal modal-open z-8">
|
||||
<div class="modal-box w-full max-w-xl">
|
||||
<h3 class="text-lg font-bold">{upload()+mediaType}</h3>
|
||||
|
||||
<div class="form-control mt-4">
|
||||
<label for="mfile" class="label">{upload() + ' ' + file()}</label>
|
||||
<input
|
||||
id="mfile"
|
||||
type="file"
|
||||
accept={acceptTypes}
|
||||
class="file-input file-input-bordered w-full"
|
||||
on:change={handleFileChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-4">
|
||||
<label for="mtitle" class="label">{media_title()}</label>
|
||||
<input id="mtitle" bind:value={newMedia.name} class="input input-bordered w-full" />
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-4">
|
||||
<label for="mdesc" class="label">{description()}</label>
|
||||
<textarea
|
||||
id="mdesc"
|
||||
bind:value={newMedia.description}
|
||||
class="textarea textarea-bordered w-full"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-4">
|
||||
<label for="mdate" class="label">{date()}</label>
|
||||
<input
|
||||
id="mdate"
|
||||
type="date"
|
||||
bind:value={newMedia.date}
|
||||
class="input input-bordered w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="modal-action">
|
||||
<button class="btn btn-outline" on:click={closeModal}>Cancel</button>
|
||||
<button class="btn btn-primary" on:click={uploadMedia}>Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Reference in New Issue
Block a user