From 3c8093a3d227a5b706976e6be59ca11f7e72beac Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 26 Apr 2024 18:50:30 -1000 Subject: [PATCH] feat: :sparkles: Implement proper login and logout using UI --- app.vue | 27 +++++++ components/buttons/base.vue | 13 +++- components/buttons/secondary.vue | 8 +- components/sidebars/navigation.vue | 78 +++++++++++++++++-- components/social-elements/notes/header.vue | 2 +- components/social-elements/notes/note.vue | 25 ++++-- .../social-elements/notifications/notif.vue | 58 +++++++------- components/social-elements/users/Account.vue | 36 ++++----- components/timelines/Notifications.vue | 6 +- components/timelines/Public.vue | 2 +- composables/AccessToken.ts | 8 ++ composables/Account.ts | 13 +++- composables/AccountSearch.ts | 20 +++-- composables/AccountTimeline.ts | 68 ---------------- composables/AppData.ts | 8 ++ composables/ExtendedDescription.ts | 12 +-- composables/Instance.ts | 12 +-- composables/Megalodon.ts | 20 ++--- composables/Note.ts | 12 +-- layouts/app.vue | 6 +- pages/[username]/index.vue | 11 ++- pages/local.vue | 2 +- pages/register/index.vue | 19 ++--- 23 files changed, 273 insertions(+), 193 deletions(-) create mode 100644 composables/AccessToken.ts create mode 100644 composables/AppData.ts diff --git a/app.vue b/app.vue index 9f3db8b..b81e7a8 100644 --- a/app.vue +++ b/app.vue @@ -13,6 +13,33 @@ useServerSeoMeta({ // Use SSR-safe IDs for Headless UI provideHeadlessUseId(() => useId()); + +const code = useRequestURL().searchParams.get("code"); + +if (code) { + const client = useMegalodon(); + const appData = useAppData(); + const tokenData = useTokenData(); + if (appData.value) { + client.value + ?.fetchAccessToken( + appData.value.client_id, + appData.value.client_secret, + code, + new URL("/", useRequestURL().origin).toString(), + ) + .then((res) => { + tokenData.value = res; + + // Remove code from URL + window.history.replaceState( + {}, + document.title, + window.location.pathname, + ); + }); + } +} \ No newline at end of file diff --git a/components/buttons/secondary.vue b/components/buttons/secondary.vue index b7e9104..b95ea07 100644 --- a/components/buttons/secondary.vue +++ b/components/buttons/secondary.vue @@ -1,5 +1,5 @@ @@ -9,7 +9,11 @@ import type { ButtonHTMLAttributes } from "vue"; interface Props extends /* @vue-ignore */ ButtonHTMLAttributes {} -defineProps(); +defineProps< + Props & { + loading?: boolean; + } +>(); \ No newline at end of file diff --git a/components/sidebars/navigation.vue b/components/sidebars/navigation.vue index 8f0aa78..74c3264 100644 --- a/components/sidebars/navigation.vue +++ b/components/sidebars/navigation.vue @@ -21,14 +21,17 @@

Account

- - - - Sign In - - - + + + Sign Out + + + + Sign In + + @@ -52,4 +55,63 @@ const timelines = ref([ icon: "tabler:home", }, ]); + +const loadingAuth = ref(false); + +const appData = useAppData(); +const tokenData = useTokenData(); +const client = useMegalodon(); + +const signIn = async () => { + loadingAuth.value = true; + + const output = await client.value?.createApp("Lysand", { + scopes: ["read", "write", "follow", "push"], + redirect_uris: new URL("/", useRequestURL().origin).toString(), + website: useBaseUrl().value, + }); + + if (!output) { + alert("Failed to create app"); + return; + } + + appData.value = output; + + const url = await client.value?.generateAuthUrl( + output.client_id, + output.client_secret, + { + scope: ["read", "write", "follow", "push"], + redirect_uri: new URL("/", useRequestURL().origin).toString(), + }, + ); + + if (!url) { + alert("Failed to generate auth URL"); + return; + } + + window.location.href = url; +}; + +const signOut = async () => { + loadingAuth.value = true; + + if (!appData.value || !tokenData.value) { + console.error("No app or token data to sign out"); + return; + } + + // Don't do anything on error, as Lysand doesn't implement the revoke endpoint yet + await client.value + ?.revokeToken( + appData.value.client_id, + tokenData.value.access_token, + tokenData.value.access_token, + ) + .catch(() => {}); + + tokenData.value = null; +}; \ No newline at end of file diff --git a/components/social-elements/notes/header.vue b/components/social-elements/notes/header.vue index ea19486..25908a9 100644 --- a/components/social-elements/notes/header.vue +++ b/components/social-elements/notes/header.vue @@ -55,7 +55,7 @@ \ No newline at end of file diff --git a/components/social-elements/users/Account.vue b/components/social-elements/users/Account.vue index 2646822..2603e09 100644 --- a/components/social-elements/users/Account.vue +++ b/components/social-elements/users/Account.vue @@ -115,29 +115,27 @@ watch( skeleton, async () => { if (skeleton.value) return; - parsedNote.value = ( + parsedNote.value = useParsedContent( props.account?.note ?? "", props.account?.emojis ?? [], [], - ) - ).value ?? ""; - parsedFields.value = props.account?.fields.map((field) => ({ - name: ( - useParsedContent( - field.name, - props.account?.emojis ?? [], - [], - ) - ).value ?? "", - value: ( - useParsedContent( - field.value, - props.account?.emojis ?? [], - [], - ) - ).value ?? "", - })) ?? []; + ).value ?? ""; + parsedFields.value = + props.account?.fields.map((field) => ({ + name: + useParsedContent( + field.name, + props.account?.emojis ?? [], + [], + ).value ?? "", + value: + useParsedContent( + field.value, + props.account?.emojis ?? [], + [], + ).value ?? "", + })) ?? []; }, { immediate: true, diff --git a/components/timelines/Notifications.vue b/components/timelines/Notifications.vue index 788fcae..2c94282 100644 --- a/components/timelines/Notifications.vue +++ b/components/timelines/Notifications.vue @@ -14,15 +14,15 @@