Skip to content

Commit

Permalink
➕ Integrate veaury
Browse files Browse the repository at this point in the history
  • Loading branch information
nwingt committed Dec 13, 2024
1 parent 24d6b21 commit e87eb9a
Show file tree
Hide file tree
Showing 16 changed files with 1,984 additions and 1,181 deletions.
43 changes: 33 additions & 10 deletions app.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
<template>
<div class="fixed inset-0 flex">
<ClientOnly>
<ReactPrivyBridge
@ready-change="userStore.setIsPrivyReady"
@authenticated-change="userStore.setIsPrivyAuthenticated"
@user-change="userStore.setPrivyUser"
@login-method-change="userStore.setPrivyLogin"
@logout-method-change="userStore.setPrivyLogout"
/>
</ClientOnly>

<div
v-if="!isPrivyReady"
class="absolute inset-0 z-20 flex flex-col items-center justify-center gap-4 bg-white"
>
<AppLogo class="h-20 mx-auto" />
<UIcon
class="w-10 h-10 mx-auto animate-spin"
name="i-heroicons-arrow-path-20-solid"
/>
</div>

<UModal
:model-value="!userStore.address"
:model-value="isPrivyReady && !isPrivyAuthenticated"
:ui="{
padding: 'p-0',
rounded: 'rounded-none lg:rounded-lg',
Expand Down Expand Up @@ -41,7 +62,7 @@
</USlideover>

<NuxtPage
:class="['overflow-y-auto', { 'opacity-0': !userStore.address }]"
:class="['overflow-y-auto', { 'opacity-0': !isPrivyAuthenticated }]"
/>

<NuxtLoadingIndicator />
Expand All @@ -51,7 +72,17 @@
</template>

<script setup lang="ts">
import { createRoot } from "react-dom/client";
import { setVeauryOptions } from "veaury";
setVeauryOptions({
react: {
createRoot,
},
});
const userStore = useUserStore();
const { isPrivyAuthenticated, isPrivyReady } = storeToRefs(userStore);
const uiStore = useUIStore();
const isMobileMenuOpen = computed({
Expand Down Expand Up @@ -110,12 +141,4 @@ useSeoMeta({
title: "book3.app",
ogTitle: "book3.app",
});
await callOnce(async () => {
try {
await userStore.fetchSettings();
} catch {
// Ignore
}
});
</script>
202 changes: 20 additions & 182 deletions components/AuthPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,98 +9,26 @@

<p
class="flex justify-center items-center text-2xl text-gray-900 dark:text-white font-bold text-center"
>
{{ $t("auth_page_tagline") }}
</p>

<div class="relative group rounded-full">
<div class="absolute -inset-[2px] rounded-[inherit] overflow-hidden">
<div
class="absolute inset-x-0 aspect-1 top-[50%] -translate-y-[50%] group-hover:rotate-[720deg] transition-transform duration-[2s] ease-[cubic-bezier(0.27,0,0.24,0.99)]"
style="
background: conic-gradient(
from 180deg,
#45e1e5 0deg,
#0052ff 86.4deg,
#b82ea4 165.6deg,
#ff9533 255.6deg,
#7fd057 320.4deg,
#45e1e5 360deg
);
"
/>
</div>
<div class="relative rounded-[inherit] bg-black">
<UButton
:label="$t('auth_page_sign_in_or_sign_up_button_label')"
color="white"
size="xl"
:disabled="!!authenticatingConnectorId"
:loading="authenticatingConnectorId === 'coinbaseWalletSDK'"
block
:ui="{ rounded: 'rounded-full' }"
@click="createWallet"
/>
</div>
</div>

<UAccordion
v-if="otherConnectors.length"
:items="[{ slot: 'connectors' }]"
:ui="{ wrapper: 'flex flex-col w-full' }"
>
<template #default="{ open }">
<UButton
class="flex justify-center items-center"
:label="$t('auth_page_sign_in_with_other_method_button_label')"
:trailing-icon="
open ? 'i-heroicons-chevron-up' : 'i-heroicons-chevron-down'
"
variant="ghost"
rounded
/>
</template>

<template #connectors>
<ul class="space-y-2">
<li v-for="connector in otherConnectors" :key="connector.name">
<UButton
:label="connector.name"
size="xl"
variant="outline"
:disabled="!!authenticatingConnectorId"
:loading="authenticatingConnectorId === connector.id"
block
@click="handleConnect(connector)"
/>
</li>
</ul>
</template>
</UAccordion>
v-text="$t('auth_page_tagline')"
/>

<UButton
:label="$t('auth_page_sign_in_or_sign_up_button_label')"
color="white"
size="xl"
:disabled="isPrivyAuthenticated"
block
:ui="{ rounded: 'rounded-full' }"
@click="login"
/>
</UCard>
</template>

<script setup lang="ts">
import {
useAccount,
useConnect,
useDisconnect,
useChainId,
useSignMessage,
type Connector,
} from "@wagmi/vue";
import { SiweMessage } from "siwe";
import { useUserStore } from "../stores/user";
const chainId = useChainId();
const { connectors, connectAsync } = useConnect();
const { disconnect, disconnectAsync } = useDisconnect();
const account = useAccount();
const userStore = useUserStore();
const toast = useToast();
const authenticatingConnectorId = ref<string | undefined>(undefined);
const { isPrivyAuthenticated, isPrivyReady } = storeToRefs(userStore);
function handleAuthError({
error,
Expand All @@ -110,8 +38,6 @@ function handleAuthError({
title?: string;
}) {
console.error(error);
authenticatingConnectorId.value = undefined;
disconnect();
toast.add({
title,
color: "red",
Expand All @@ -121,102 +47,14 @@ function handleAuthError({
});
}
const otherConnectors = computed(() =>
connectors.filter((connector) => connector.id !== "coinbaseWalletSDK"),
);
const { signMessageAsync } = useSignMessage({
mutation: {
onError: (error) => {
handleAuthError({ error, title: "Failed to sign message." });
},
onSuccess: async (signature, { message }) => {
if (!signature) {
handleAuthError({ error: new Error("Failed to sign message.") });
return;
}
const address = account.address?.value;
if (!address) {
handleAuthError({ error: new Error("Failed to fetch address.") });
return;
}
try {
await userStore.login({ address, signature, message });
} catch (error) {
handleAuthError({ error: error as Error, title: "Failed to login." });
return;
}
authenticatingConnectorId.value = undefined;
},
},
});
async function handleConnect(connector: Connector) {
if (account.isConnected) {
await disconnectAsync();
function login() {
if (!isPrivyReady.value || isPrivyAuthenticated.value) {
return;
}
authenticatingConnectorId.value = connector.id;
await connectAsync(
{
connector,
chainId: chainId.value,
},
{
onError(error) {
handleAuthError({ error, title: "Failed to connect." });
},
onSuccess: async () => {
let nonce;
try {
nonce = await $fetch("/api/users/nonce");
} catch (error) {
handleAuthError({
error: error as Error,
title: "Failed to fetch nonce.",
});
return;
}
if (!nonce) {
console.error("Failed to fetch nonce.");
disconnect();
return;
}
const address = account.address?.value;
if (!address) {
handleAuthError({ error: new Error("Failed to get address.") });
return;
}
const swieMessage = new SiweMessage({
domain: document.location.host,
address,
chainId: account.chainId?.value,
uri: document.location.origin,
version: "1",
statement: "Login to book3.app",
nonce,
});
const message = swieMessage.prepareMessage();
await signMessageAsync({ account: address, message });
},
},
);
}
function createWallet() {
const coinbaseWalletConnector = connectors.find(
(connector) => connector.id === "coinbaseWalletSDK",
);
if (coinbaseWalletConnector) {
handleConnect(coinbaseWalletConnector);
try {
userStore.login();
} catch (error) {
handleAuthError({ error: error as Error });
}
}
</script>
25 changes: 25 additions & 0 deletions components/ReactPrivyBridge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<PrivyComponent
@ready-change="$emit('ready-change', $event)"
@authenticated-change="$emit('authenticated-change', $event)"
@user-change="$emit('user-change', $event)"
@login-method-change="$emit('login-method-change', $event)"
@logout-method-change="$emit('logout-method-change', $event)"
/>
</template>

<script setup>
import { applyPureReactInVue } from "veaury";
import VeauryPrivy from "../react_app/PrivyApp.jsx";
const PrivyComponent = applyPureReactInVue(VeauryPrivy);
defineEmits([
"ready-change",
"authenticated-change",
"user-change",
"login-method-change",
"logout-method-change",
]);
</script>
18 changes: 10 additions & 8 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
import veauryVitePlugins from "veaury/vite/index.js";

export default defineNuxtConfig({
app: {
rootAttrs: {
class: "h-full min-h-svh",
},
},
compatibilityDate: "2024-04-03",
runtimeConfig: {
sessionSecret:
process.env.SESSION_SECRET || "00000000-0000-0000-0000-000000000000",
public: {
sessionName: "book3_app_session",
},
},
devtools: { enabled: true },
modules: [
"@nuxt/ui",
"@nuxt/eslint",
"@pinia/nuxt",
"@wagmi/vue/nuxt",
"@vueuse/nuxt",
"@nuxtjs/i18n",
],
Expand All @@ -29,4 +23,12 @@ export default defineNuxtConfig({
{ code: "zh-Hant", name: "繁體中文" },
],
},
vite: {
plugins: [
veauryVitePlugins({
type: "vue",
isNuxt: true,
}),
],
},
});
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@
"@nuxt/ui": "^2.17.0",
"@nuxtjs/i18n": "^8.4.0",
"@pinia/nuxt": "^0.5.3",
"@tanstack/vue-query": "^5.51.9",
"@privy-io/react-auth": "^1.96.2",
"@vitejs/plugin-react": "^4.3.4",
"@vueuse/core": "^11.0.0",
"@vueuse/nuxt": "^11.0.0",
"@wagmi/vue": "^0.0.32",
"dexie": "^4.0.8",
"epubjs": "^0.3.93",
"ethers": "^6.13.2",
"nuxt": "^3.12.3",
"siwe": "^2.3.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"uuid": "^10.0.0",
"viem": "2.x",
"veaury": "^2.6.1",
"vue": "latest"
},
"devDependencies": {
Expand Down
Loading

0 comments on commit e87eb9a

Please sign in to comment.