1
0
Fork 0
mirror of https://github.com/seanmorley15/AdventureLog.git synced 2025-07-25 15:59:38 +02:00

Allow for Sharing of Collections to other Public Users

This commit is contained in:
Sean Morley 2024-09-10 17:16:05 -04:00 committed by GitHub
commit 4a293798eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 1368 additions and 311 deletions

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import type { Adventure, User } from '$lib/types';
import type { Adventure, Collection, User } from '$lib/types';
const dispatch = createEventDispatcher();
import Launch from '~icons/mdi/launch';
@ -21,8 +21,8 @@
import ImageDisplayModal from './ImageDisplayModal.svelte';
export let type: string;
export let user: User | null;
export let collection: Collection | null = null;
let isCollectionModalOpen: boolean = false;
let isWarningModalOpen: boolean = false;
@ -161,7 +161,7 @@
{/if}
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl"
>
<figure>
{#if adventure.images && adventure.images.length > 0}
@ -209,19 +209,17 @@
</button>
</div>
<div>
{#if adventure.type == 'visited' && user?.pk == adventure.user_id}
{#if adventure.type == 'visited'}
<div class="badge badge-primary">Visited</div>
{:else if user?.pk == adventure.user_id && adventure.type == 'planned'}
{:else if adventure.type == 'planned'}
<div class="badge badge-secondary">Planned</div>
{:else if (user?.pk !== adventure.user_id && adventure.type == 'planned') || adventure.type == 'visited'}
<div class="badge badge-secondary">Adventure</div>
{:else if user?.pk == adventure.user_id && adventure.type == 'lodging'}
{:else if adventure.type == 'lodging'}
<div class="badge badge-success">Lodging</div>
{:else if adventure.type == 'dining'}
<div class="badge badge-accent">Dining</div>
{/if}
<div class="badge badge-neutral">{adventure.is_public ? 'Public' : 'Private'}</div>
<div class="badge badge-secondary">{adventure.is_public ? 'Public' : 'Private'}</div>
</div>
{#if adventure.location && adventure.location !== ''}
<div class="inline-flex items-center">
@ -254,9 +252,9 @@
<div class="card-actions justify-end mt-2">
<!-- action options dropdown -->
{#if type != 'link'}
{#if user?.pk == adventure.user_id}
{#if adventure.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-neutral">
<div tabindex="0" role="button" class="btn btn-neutral-200">
<DotsHorizontal class="w-6 h-6" />
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@ -272,18 +270,18 @@
<button class="btn btn-neutral mb-2" on:click={editAdventure}>
<FileDocumentEdit class="w-6 h-6" />Edit {keyword}
</button>
{#if adventure.type == 'visited'}
{#if adventure.type == 'visited' && user?.pk == adventure.user_id}
<button class="btn btn-neutral mb-2" on:click={changeType('planned')}
><FormatListBulletedSquare class="w-6 h-6" />Change to Plan</button
>
{/if}
{#if adventure.type == 'planned'}
{#if adventure.type == 'planned' && user?.pk == adventure.user_id}
<button class="btn btn-neutral mb-2" on:click={changeType('visited')}
><CheckBold class="w-6 h-6" />Mark Visited</button
>
{/if}
<!-- remove from adventure -->
{#if adventure.collection && (adventure.type == 'visited' || adventure.type == 'planned')}
{#if adventure.collection && (adventure.type == 'visited' || adventure.type == 'planned') && user?.pk == adventure.user_id}
<button class="btn btn-neutral mb-2" on:click={removeFromCollection}
><LinkVariantRemove class="w-6 h-6" />Remove from Collection</button
>
@ -309,8 +307,9 @@
</ul>
</div>
{:else}
<button class="btn btn-neutral mb-2" on:click={() => goto(`/adventures/${adventure.id}`)}
><Launch class="w-6 h-6" /></button
<button
class="btn btn-neutral-200 mb-2"
on:click={() => goto(`/adventures/${adventure.id}`)}><Launch class="w-6 h-6" /></button
>
{/if}
{/if}

View file

@ -627,22 +627,24 @@
</button>
{/if}
</div>
<div>
<div class="mt-2">
<div>
<label for="is_public"
>Public <Earth class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br />
<input
type="checkbox"
class="toggle toggle-primary"
id="is_public"
name="is_public"
bind:checked={adventure.is_public}
/>
{#if !collection_id}
<div>
<div class="mt-2">
<div>
<label for="is_public"
>Public <Earth class="inline-block -mt-1 mb-1 w-6 h-6" /></label
><br />
<input
type="checkbox"
class="toggle toggle-primary"
id="is_public"
name="is_public"
bind:checked={adventure.is_public}
/>
</div>
</div>
</div>
</div>
{/if}
</div>
<div class="divider"></div>
<h2 class="text-2xl font-semibold mb-2 mt-2">Location Information</h2>

View file

@ -12,7 +12,7 @@
<div class="dropdown dropdown-bottom dropdown-end" tabindex="0" role="button">
<div class="avatar placeholder">
<div class="bg-neutral text-neutral-content rounded-full w-10 ml-4">
<div class="bg-neutral rounded-full text-neutral-200 w-10 ml-4">
{#if user.profile_pic}
<img src={user.profile_pic} alt="User Profile" />
{:else}
@ -24,7 +24,7 @@
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<ul
tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow bg-primary-content mt-2 rounded-box w-52"
class="dropdown-content z-[1] text-neutral-200 menu p-2 shadow bg-neutral mt-2 rounded-box w-52"
>
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y-missing-attribute -->
@ -32,6 +32,7 @@
<li><button on:click={() => goto('/profile')}>Profile</button></li>
<li><button on:click={() => goto('/adventures')}>My Adventures</button></li>
<li><button on:click={() => goto('/activities')}>My Activities</button></li>
<li><button on:click={() => goto('/shared')}>Shared With Me</button></li>
<li><button on:click={() => goto('/settings')}>User Settings</button></li>
<form method="post">
<li><button formaction="/?/logout">Logout</button></li>

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { addToast } from '$lib/toasts';
import type { Checklist, User } from '$lib/types';
import type { Checklist, Collection, User } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
@ -10,6 +10,7 @@
export let checklist: Checklist;
export let user: User | null = null;
export let collection: Collection | null = null;
function editChecklist() {
dispatch('edit', checklist);
@ -29,7 +30,7 @@
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl overflow-hidden text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl overflow-hidden"
>
<div class="card-body">
<div class="flex justify-between">
@ -51,10 +52,10 @@
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
><Launch class="w-6 h-6" />Open Details</button
> -->
<button class="btn btn-neutral mb-2" on:click={editChecklist}>
<button class="btn btn-neutral-200 mb-2" on:click={editChecklist}>
<Launch class="w-6 h-6" />Open
</button>
{#if checklist.user_id == user?.pk}
{#if checklist.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<button
id="delete_adventure"
data-umami-event="Delete Checklist"

View file

@ -33,7 +33,7 @@
{
name: newItem,
is_checked: newStatus,
id: 0,
id: '',
user_id: 0,
checklist: 0,
created_at: '',
@ -135,7 +135,7 @@
<p class="font-semibold text-md mb-2">Editing checklist {initialName}</p>
{/if}
{#if (checklist && user?.pk == checklist?.user_id) || !checklist}
{#if (checklist && user?.pk == checklist?.user_id) || (user && collection && collection.shared_with.includes(user.uuid)) || !checklist}
<form on:submit|preventDefault>
<div class="form-control mb-2">
<label for="name">Name</label>

View file

@ -16,10 +16,12 @@
import DotsHorizontal from '~icons/mdi/dots-horizontal';
import TrashCan from '~icons/mdi/trashcan';
import DeleteWarning from './DeleteWarning.svelte';
import ShareModal from './ShareModal.svelte';
const dispatch = createEventDispatcher();
export let type: String | undefined | null;
let isShareModalOpen: boolean = false;
// export let type: String;
@ -77,8 +79,12 @@
/>
{/if}
{#if isShareModalOpen}
<ShareModal {collection} on:close={() => (isShareModalOpen = false)} />
{/if}
<div
class="card min-w-max lg:w-96 md:w-80 sm:w-60 xs:w-40 bg-primary-content shadow-xl text-base-content"
class="card min-w-max lg:w-96 md:w-80 sm:w-60 xs:w-40 bg-neutral text-neutral-content shadow-xl"
>
<div class="card-body">
<div class="flex justify-between">
@ -90,7 +96,7 @@
</button>
</div>
<div class="inline-flex gap-2 mb-2">
<div class="badge badge-neutral">{collection.is_public ? 'Public' : 'Private'}</div>
<div class="badge badge-secondary">{collection.is_public ? 'Public' : 'Private'}</div>
{#if collection.is_archived}
<div class="badge badge-warning">Archived</div>
{/if}
@ -117,7 +123,7 @@
</button>
{:else}
<div class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-neutral">
<div tabindex="0" role="button" class="btn btn-neutral-200">
<DotsHorizontal class="w-6 h-6" />
</div>
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
@ -125,7 +131,7 @@
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box z-[1] w-52 p-2 shadow"
>
{#if type != 'link'}
{#if type != 'link' && type != 'viewonly'}
<button
class="btn btn-neutral mb-2"
on:click={() => goto(`/collections/${collection.id}`)}
@ -135,6 +141,9 @@
<button class="btn btn-neutral mb-2" on:click={editAdventure}>
<FileDocumentEdit class="w-6 h-6" />Edit Collection
</button>
<button class="btn btn-neutral mb-2" on:click={() => (isShareModalOpen = true)}>
<FileDocumentEdit class="w-6 h-6" />Share
</button>
{/if}
{#if collection.is_archived}
<button class="btn btn-neutral mb-2" on:click={() => archiveCollection(false)}>
@ -153,6 +162,13 @@
><TrashCan class="w-6 h-6" />Delete</button
>
{/if}
{#if type == 'viewonly'}
<button
class="btn btn-neutral mb-2"
on:click={() => goto(`/collections/${collection.id}`)}
><Launch class="w-5 h-5 mr-1" />Open Details</button
>
{/if}
</ul>
</div>
{/if}

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { getFlag } from '$lib';
import { continentCodeToString, getFlag } from '$lib';
import type { Country } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
@ -13,7 +13,7 @@
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl overflow-hidden text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl overflow-hidden"
>
<figure>
<!-- svelte-ignore a11y-img-redundant-alt -->
@ -21,6 +21,7 @@
</figure>
<div class="card-body">
<h2 class="card-title overflow-ellipsis">{country.name}</h2>
<div class="badge badge-primary">{continentCodeToString(country.continent)}</div>
<div class="card-actions justify-end">
<!-- <button class="btn btn-info" on:click={moreInfo}>More Info</button> -->
<button class="btn btn-primary" on:click={nav}>Open</button>

View file

@ -11,7 +11,9 @@
import Flower from '~icons/mdi/flower';
import Water from '~icons/mdi/water';
import AboutModal from './AboutModal.svelte';
import AccountMultiple from '~icons/mdi/account-multiple';
import Avatar from './Avatar.svelte';
import PaletteOutline from '~icons/mdi/palette-outline';
import { page } from '$app/stores';
let query: string = '';
@ -81,6 +83,9 @@
<li>
<button on:click={() => goto('/map')}>Map</button>
</li>
<li>
<button on:click={() => goto('/users')}>Users</button>
</li>
{/if}
{#if !data.user}
@ -133,6 +138,11 @@
<li>
<button class="btn btn-neutral" on:click={() => goto('/map')}>Map</button>
</li>
<li>
<button class="btn btn-neutral" on:click={() => goto('/users')}
><AccountMultiple /></button
>
</li>
{/if}
{#if !data.user}
@ -184,6 +194,10 @@
on:click={() => (window.location.href = 'https://docs.adventurelog.app/')}
>Documentation</button
>
<button
class="btn btn-sm mt-2"
on:click={() => (window.location.href = 'https://discord.gg/wRbQ9Egr8C')}>Discord</button
>
<p class="font-bold m-4 text-lg">Theme Selection</p>
<form method="POST" use:enhance={submitUpdateTheme}>
<li>
@ -202,7 +216,12 @@
</li>
<li>
<button formaction="/?/setTheme&theme=forest">Forest<Forest class="w-6 h-6" /></button>
<button formaction="/?/setTheme&theme=garden">Garden<Flower class="w-6 h-6" /></button>
<button formaction="/?/setTheme&theme=aestheticLight"
>Aesthetic Light<PaletteOutline class="w-6 h-6" /></button
>
<button formaction="/?/setTheme&theme=aestheticDark"
>Aesthetic Dark<PaletteOutline class="w-6 h-6" /></button
>
<button formaction="/?/setTheme&theme=aqua">Aqua<Water class="w-6 h-6" /></button>
</li>
</form>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { addToast } from '$lib/toasts';
import type { Note, User } from '$lib/types';
import type { Collection, Note, User } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
@ -11,6 +11,7 @@
export let note: Note;
export let user: User | null = null;
export let collection: Collection | null = null;
function editNote() {
dispatch('edit', note);
@ -30,7 +31,7 @@
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl overflow-hidden text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md overflow-hidden bg-neutral text-neutral-content shadow-xl"
>
<div class="card-body">
<div class="flex justify-between">
@ -52,10 +53,10 @@
<!-- <button class="btn btn-neutral mb-2" on:click={() => goto(`/notes/${note.id}`)}
><Launch class="w-6 h-6" />Open Details</button
> -->
<button class="btn btn-neutral mb-2" on:click={editNote}>
<button class="btn btn-neutral-200 mb-2" on:click={editNote}>
<Launch class="w-6 h-6" />Open
</button>
{#if note.user_id == user?.pk}
{#if note.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<button
id="delete_adventure"
data-umami-event="Delete Adventure"

View file

@ -4,6 +4,7 @@
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
import { onMount } from 'svelte';
import ShareModal from './ShareModal.svelte';
let modal: HTMLDialogElement;
export let note: Note | null = null;
@ -113,7 +114,7 @@
<p class="font-semibold text-md mb-2">Editing note {initialName}</p>
{/if}
{#if (note && user?.pk == note?.user_id) || !note}
{#if (note && user?.pk == note?.user_id) || (collection && user && collection.shared_with.includes(user.uuid)) || !note}
<form on:submit|preventDefault>
<div class="form-control mb-2">
<label for="name">Name</label>

View file

@ -54,7 +54,7 @@
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl overflow-hidden text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl overflow-hidden"
>
<div class="card-body">
{#if region.name_en && region.name !== region.name_en}

View file

@ -0,0 +1,118 @@
<script lang="ts">
import type { Collection, User } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
import { onMount } from 'svelte';
import UserCard from './UserCard.svelte';
import { addToast } from '$lib/toasts';
let modal: HTMLDialogElement;
export let collection: Collection;
let allUsers: User[] = [];
let sharedWithUsers: User[] = [];
let notSharedWithUsers: User[] = [];
async function share(user: User) {
let res = await fetch(`/api/collections/${collection.id}/share/${user.uuid}/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (res.ok) {
sharedWithUsers = sharedWithUsers.concat(user);
collection.shared_with.push(user.uuid);
notSharedWithUsers = notSharedWithUsers.filter((u) => u.uuid !== user.uuid);
addToast('success', `Shared ${collection.name} with ${user.first_name} ${user.last_name}`);
}
}
async function unshare(user: User) {
let res = await fetch(`/api/collections/${collection.id}/unshare/${user.uuid}/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (res.ok) {
notSharedWithUsers = notSharedWithUsers.concat(user);
collection.shared_with = collection.shared_with.filter((u) => u !== user.uuid);
sharedWithUsers = sharedWithUsers.filter((u) => u.uuid !== user.uuid);
addToast('success', `Unshared ${collection.name} with ${user.first_name} ${user.last_name}`);
}
}
onMount(async () => {
modal = document.getElementById('my_modal_1') as HTMLDialogElement;
if (modal) {
modal.showModal();
}
let res = await fetch(`/auth/users/`);
if (res.ok) {
let data = await res.json();
allUsers = data;
sharedWithUsers = allUsers.filter((user) => collection.shared_with.includes(user.uuid));
notSharedWithUsers = allUsers.filter((user) => !collection.shared_with.includes(user.uuid));
console.log(sharedWithUsers);
console.log(notSharedWithUsers);
}
});
function close() {
dispatch('close');
}
function handleKeydown(event: KeyboardEvent) {
if (event.key === 'Escape') {
dispatch('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 w-11/12 max-w-5xl" role="dialog" on:keydown={handleKeydown} tabindex="0">
<h3 class="font-bold text-lg">Share {collection.name}</h3>
<p class="py-1">Share this collection with other users.</p>
<div class="divider"></div>
<h3 class="font-bold text-md">Shared With</h3>
<ul>
{#each sharedWithUsers as user}
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
<UserCard
{user}
shared_with={collection.shared_with}
sharing={true}
on:share={(event) => share(event.detail)}
on:unshare={(event) => unshare(event.detail)}
/>
</div>
{/each}
{#if sharedWithUsers.length === 0}
<p class="text-neutral-content">No users shared with</p>
{/if}
</ul>
<div class="divider"></div>
<h3 class="font-bold text-md">Not Shared With</h3>
<ul>
{#each notSharedWithUsers as user}
<div class="flex flex-wrap gap-4 mr-4 justify-center content-center">
<UserCard
{user}
shared_with={collection.shared_with}
sharing={true}
on:share={(event) => share(event.detail)}
on:unshare={(event) => unshare(event.detail)}
/>
</div>
{/each}
{#if notSharedWithUsers.length === 0}
<p class="text-neutral-content">No users not shared with</p>
{/if}
</ul>
<button class="btn btn-primary mt-4" on:click={close}>Close</button>
</div>
</dialog>

View file

@ -1,22 +1,17 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import Launch from '~icons/mdi/launch';
import TrashCanOutline from '~icons/mdi/trash-can-outline';
import FileDocumentEdit from '~icons/mdi/file-document-edit';
import { goto } from '$app/navigation';
import type { Collection, Transportation, User } from '$lib/types';
import { addToast } from '$lib/toasts';
import Plus from '~icons/mdi/plus';
import ArrowDownThick from '~icons/mdi/arrow-down-thick';
const dispatch = createEventDispatcher();
export let transportation: Transportation;
export let user: User | null = null;
export let collection: Collection | null = null;
function editTransportation() {
dispatch('edit', transportation);
@ -40,7 +35,7 @@
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-primary-content shadow-xl text-base-content"
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl"
>
<div class="card-body">
<h2 class="card-title overflow-ellipsis">{transportation.name}</h2>
@ -64,7 +59,7 @@
{/if}
</div>
{#if user?.pk === transportation.user_id}
{#if transportation.user_id == user?.pk || (collection && user && collection.shared_with.includes(user.uuid))}
<div class="card-actions justify-end">
<button on:click={deleteTransportation} class="btn btn-secondary"
><TrashCanOutline class="w-5 h-5 mr-1" /></button

View file

@ -0,0 +1,51 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { continentCodeToString, getFlag } from '$lib';
import type { User } from '$lib/types';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
import Calendar from '~icons/mdi/calendar';
export let sharing: boolean = false;
export let shared_with: string[] | undefined = undefined;
export let user: User;
</script>
<div
class="card w-full max-w-xs sm:max-w-sm md:max-w-md lg:max-w-md xl:max-w-md bg-neutral text-neutral-content shadow-xl"
>
<div class="card-body">
<div>
{#if user.profile_pic}
<div class="avatar">
<div class="w-24 rounded-full">
<img src={user.profile_pic} alt={user.username} />
</div>
</div>
{/if}
<h2 class="card-title overflow-ellipsis">{user.first_name} {user.last_name}</h2>
</div>
<p class="text-sm text-neutral-content">{user.username}</p>
{#if user.is_staff}
<div class="badge badge-primary">Admin</div>
{/if}
<!-- member since -->
<div class="flex items-center space-x-2">
<Calendar class="w-4 h-4 mr-1" />
<p class="text-sm text-neutral-content">
{user.date_joined ? 'Joined ' + new Date(user.date_joined).toLocaleDateString() : ''}
</p>
</div>
<div class="card-actions justify-end">
{#if !sharing}
<button class="btn btn-primary" on:click={() => goto(`/user/${user.uuid}`)}>View</button>
{:else if shared_with && !shared_with.includes(user.uuid)}
<button class="btn btn-primary" on:click={() => dispatch('share', user)}>Share</button>
{:else}
<button class="btn btn-primary" on:click={() => dispatch('unshare', user)}>Unshare</button>
{/if}
</div>
</div>
</div>