Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"dependencies": {
"@beyonk/svelte-notifications": "^4.2.0",
"@blues-inc/notehub-js": "^1.0.17",
"@ory/client": "^1.6.2",
"chart.js": "^4.4.0",
"date-fns": "^2.30.0",
"mapbox-gl": "^2.15.0",
Expand Down
17 changes: 16 additions & 1 deletion src/lib/layout/Header.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import { get } from 'svelte/store';
import { onMount } from 'svelte';
import { afterNavigate } from '$app/navigation';
import CloseIcon from '$lib/icons/CloseIcon.svelte';
Expand All @@ -10,6 +11,8 @@
AirnoteDevice,
PotentiallyNullDeviceDetails
} from '$lib/services/DeviceModel';
import { identity } from '$lib/stores/identityStore';
import { fetchOryLoginUrl } from '$lib/ory/kratos';

afterNavigate(() => {
if (menuOpen === false) return;
Expand All @@ -26,13 +29,20 @@
let activePage: string | null = '';
$: activePage = $page.route.id;

onMount(() => {
let userIdentity = get(identity);
let oryLoginUrl = '';

onMount(async () => {
const location = window.location;
const currentDevice: AirnoteDevice = getCurrentDeviceFromUrl(location);

pin = currentDevice.pin ? currentDevice.pin : '';
productUID = currentDevice.productUID ? currentDevice.productUID : '';
deviceUID = currentDevice.deviceUID ? currentDevice.deviceUID : '';

if (userIdentity === null) {
oryLoginUrl = await fetchOryLoginUrl();
}
});
</script>

Expand Down Expand Up @@ -68,6 +78,11 @@
</a>
</li>
{/if}
{#if userIdentity !== null && userIdentity.traits.full_name !== ''}
<li>Hi, {userIdentity?.traits.full_name}</li>
{:else if userIdentity === null && oryLoginUrl !== ''}
<li><a href={oryLoginUrl}>Sign in</a></li>
{/if}
</ul>
<button class="svg-button" on:click={toggleMenu}>
{#if menuOpen}<CloseIcon />{/if}
Expand Down
14 changes: 14 additions & 0 deletions src/lib/ory/httpConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Configuration, FrontendApi } from '@ory/client';
import { PUBLIC_ORY_SDK_URL } from '$env/static/public';

// PUBLIC_ORY_SDK_URL is set to http://localhost:4000 in local dev as that's the default for Ory Tunnel: https://www.ory.sh/docs/cli/ory-tunnel
const basePath = PUBLIC_ORY_SDK_URL;

export const oryFrontendApi = new FrontendApi(
new Configuration({
basePath: basePath,
baseOptions: {
withCredentials: true
}
})
);
39 changes: 39 additions & 0 deletions src/lib/ory/kratos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { oryFrontendApi } from '$lib/ory/httpConfig';

export async function fetchOrySessionIdentity() {
try {
const res = await oryFrontendApi.toSession();
return res.data.identity;
} catch (err) {
console.error(err);
// todo handle other possible error states in the future
if (err.response.status === 401) {
console.log('no valid session found');
return;
}
}
}

export async function fetchOryLoginUrl() {
try {
const res = await oryFrontendApi.createBrowserLoginFlow();
console.log('res', res.data.request_url);
return res.data.request_url;
} catch (err) {
// todo handle with better error messaging in the future
console.error('Error creating login flow ', err);
return;
}
}

export async function fetchOryLogoutUrl() {
try {
const res = await oryFrontendApi.createBrowserLogoutFlow();

return res.data.logout_url;
} catch (err) {
// todo handle with better error messaging in the future
console.error('Error creating logout flow ', err);
return;
}
}
11 changes: 11 additions & 0 deletions src/lib/ory/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface KratosIdentity {
id: string;
traits: {
account_uid: string;
full_name: string;
email: string;
};
state: string;
created_at: string;
updated_at: string;
}
4 changes: 4 additions & 0 deletions src/lib/stores/identityStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { writable } from 'svelte/store';
import type { KratosIdentity } from '$lib/ory/types';

export const identity = writable<KratosIdentity | null>(null);
12 changes: 12 additions & 0 deletions src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { identity } from '$lib/stores/identityStore';
import { fetchOrySessionIdentity } from '$lib/ory/kratos';

// store user's Ory identity session for use throughout the rest of the app
export async function load() {
const userIdentity = await fetchOrySessionIdentity();

// if userIdentity is not undefined or null, set the identity store
if (userIdentity !== undefined && userIdentity !== null) {
identity.set(userIdentity);
}
}
29 changes: 29 additions & 0 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
<script lang="ts">
import { onMount } from 'svelte';
import { get } from 'svelte/store';
import { identity } from '$lib/stores/identityStore';
import { fetchOryLoginUrl, fetchOryLogoutUrl } from '$lib/ory/kratos';

let oryLoginUrl: any = '';
let oryLogoutUrl: any = '';
let userIdentity = get(identity);

onMount(async () => {
if (userIdentity === null) {
oryLoginUrl = await fetchOryLoginUrl();
} else {
oryLogoutUrl = await fetchOryLogoutUrl();
}
});
</script>

<svelte:head>
<title>Welcome to Airnote</title>
</svelte:head>
Expand Down Expand Up @@ -37,6 +56,16 @@
>
</section>

<section>
{#if oryLoginUrl !== '' && userIdentity === null}
<p>Sign in to Airnote</p>
<a class="btn" href={oryLoginUrl}>Sign in</a>
{:else if oryLogoutUrl !== '' && userIdentity !== null}
<p>Welcome back {userIdentity.traits.full_name}</p>
<a class="btn" href={oryLogoutUrl}>Sign Out</a>
{/if}
</section>

<style>
h1 {
text-align: center;
Expand Down