Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cookie consent #615

Merged
merged 12 commits into from
Jan 9, 2024
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"e2e": "playwright test tests/e2e"
},
"dependencies": {
"@appwrite.io/console": "^0.4.2",
"@appwrite.io/console": "^0.5.0",
"@appwrite.io/pink": "0.2.0",
"@appwrite.io/pink-icons": "0.2.0",
"@popperjs/core": "^2.11.8",
Expand Down
133 changes: 133 additions & 0 deletions src/lib/components/consent.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<script lang="ts" context="module">
type Consent = {
key: string;
accepted: Record<string, boolean>;
};
export const settings = writable<boolean>(false);
export const show = writable<boolean>(false);
export const consent = writable<Consent>(
JSON.parse(globalThis?.localStorage?.getItem('consent') ?? null)
);
consent.subscribe((value) => {
if (browser) {
globalThis.localStorage.setItem('consent', JSON.stringify(value));
}
});
</script>

<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import { Modal } from '.';
import { Button } from '$lib/elements/forms';
import { writable } from 'svelte/store';
import { browser } from '$app/environment';

const key = new Date('2023-11-07');
const dispatch = createEventDispatcher();

let selected = {};

$: if ($settings) {
selected = $consent?.accepted ?? {};
}

onMount(() => {
if ($consent) {
const date = new Date($consent.key);
if (key > date) {
show.set(true);
}
} else {
show.set(true);
}
});

function saveSettings(obj: Consent) {
consent.set(obj);
}

function confirmChoices(choices: Consent['accepted']) {
const consent = {
key: key.toISOString(),
accepted: choices
};
saveSettings(consent);
dispatch('confirm', consent);
show.set(false);
settings.set(false);
}

function acceptAll() {
confirmChoices({
analytics: true
});
}

function rejectAll() {
confirmChoices({});
}
</script>

{#if $show}
<div class="card is-consent">
<p>
By clicking "Accept all", you agree to the storing of cookies on your device to analyze
site usage.
</p>

<div class="u-flex u-margin-block-start-16 u-main-space-between u-cross-center">
<div>
<Button class="u-padding-inline-0" text on:click={() => settings.set(true)}
>Cookie settings</Button>
</div>
<div class="u-flex u-gap-16">
<Button secondary on:click={rejectAll}>Only required</Button>
<Button secondary on:click={acceptAll}>Accept all</Button>
</div>
</div>
</div>
{/if}

<Modal bind:show={$settings} title="Cookie Preferences">
<p>
We use cookies to improve your site experience. The "strictly necessary" cookies are
required for Appwrite to function.
</p>
<div class="u-flex-vertical u-gap-24 u-width-full-line" style:margin-block-end="24px">
<div class="u-flex u-gap-8">
<input type="checkbox" checked disabled />
<div>
<span class="text u-bold">Strictly Necessary Cookies</span>
<p class="text u-margin-block-start-8">
These are the cookies required for Appwrite to function.
</p>
</div>
</div>
<div class="u-flex u-gap-8">
<input id="analytics" type="checkbox" bind:checked={selected['analytics']} />
<div>
<label for="analytics" class="text u-bold">Product Analytics</label>
<span class="">(optional)</span>
<p class="text u-margin-block-start-8">
We include analytics cookies to understand how you use our product and design
better experiences.
</p>
</div>
</div>
</div>
<svelte:fragment slot="footer">
<Button text external href="https://appwrite.io/privacy">Privacy Policy</Button>
<Button on:click={() => confirmChoices(selected)}>Save preferences</Button>
</svelte:fragment>
</Modal>

<style lang="scss">
.card.is-consent {
position: fixed;
padding: 1.5rem;
bottom: 1rem;
right: 1rem;
z-index: 100;
max-width: 600px;
}
</style>
14 changes: 14 additions & 0 deletions src/lib/layout/footer.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script>
import { settings } from '$lib/components/consent.svelte';
import { clickOnEnter } from '$lib/helpers/a11y';
import { isCloud } from '$lib/system';
import { version } from '$routes/console/store';

Expand Down Expand Up @@ -39,6 +41,18 @@
<span class="text">Privacy</span>
</a>
</li>
{#if isCloud}
<li class="inline-links-item">
<span
style:cursor="pointer"
role="button"
tabindex="0"
on:keyup={clickOnEnter}
on:click={() => settings.set(true)}>
<span class="text">Cookies</span>
</span>
</li>
{/if}
</ul>
</div>
<div class="main-footer-end">
Expand Down
6 changes: 5 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import Loading from './loading.svelte';
import { loading, requestedMigration } from './store';
import { parseIfString } from '$lib/helpers/object';
import Consent, { consent } from '$lib/components/consent.svelte';

if (browser) {
window.VERCEL_ANALYTICS_ID = import.meta.env.VERCEL_ANALYTICS_ID?.toString() ?? false;
Expand Down Expand Up @@ -51,7 +52,7 @@
/**
* LogRocket
*/
if (isCloud && isTrackingAllowed()) {
if ($consent?.accepted?.analytics && isCloud && isTrackingAllowed()) {
LogRocket.init('rgthvf/appwrite', {
dom: {
inputSanitizer: true
Expand Down Expand Up @@ -124,6 +125,9 @@
</script>

<Notifications />
{#if isCloud}
<Consent />
{/if}

<slot />

Expand Down
2 changes: 1 addition & 1 deletion src/routes/console/account/delete.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

async function deleteAccount() {
try {
await sdk.forConsole.account.updateStatus();
await sdk.forConsole.account.delete();
await invalidate(Dependencies.ACCOUNT);
showDelete = false;
addNotification({
Expand Down