# Vue

> Provider, composables y el botón hospedado en una aplicación de Vue.


```bash
npm install @andco/sdk @andco/sdk-vue
```

## Montar el provider

```vue title="src/App.vue"
<script setup lang="ts">
import { AndcoProvider } from "@andco/sdk-vue";
import Account from "./Account.vue";

const clientOptions = {
  clientId: import.meta.env.VITE_ANDCO_CLIENT_ID,
  redirectTo: new URL("/", window.location.origin).href,
  initialScopes: ["openid", "email", "profile"],
};
</script>

<template>
  <AndcoProvider :client-options="clientOptions">
    <Account />
  </AndcoProvider>
</template>
```

Es un componente y no un plugin global a propósito: un plugin construiría el mismo contexto con el mismo código, pero haría imposible tener dos instancias y dejaría estado global vivo después de desmontar.

## Leer la sesión

```vue title="src/Account.vue"
<script setup lang="ts">
import { useAndcoSession } from "@andco/sdk-vue";

const session = useAndcoSession();
</script>

<template>
  <p v-if="session === undefined">Cargando…</p>
  <p v-else-if="session">{{ session.user.email }}</p>
  <p v-else>Sin sesión</p>
</template>
```

`useAndcoSession()` devuelve un `Ref<AndcoSession | null | undefined>` con los tres estados y cambia en cada republicación, rotaciones incluidas. `useAndcoUser()` devuelve un `ComputedRef<AndcoUser | null | undefined>` — no la persona directamente — que cambia solo cuando cambia la persona.

## El botón

```vue
<script setup lang="ts">
import { AndcoButton } from "@andco/sdk-vue";
</script>

<template>
  <AndcoButton
    :authorization="{ scopes: ['openid', 'email', 'profile'] }"
    @complete="reload"
    @error="(error) => (message = error.message)"
  />
</template>
```

## Autenticar y llamar a la API

`useAndco()` devuelve un objeto de *getters*, no un `ref`: `andco.rest` y
`andco.auth` se leen en vivo, sin `.value`.

```vue
<script setup lang="ts">
import { useAndco } from "@andco/sdk-vue";
import { onMounted, ref } from "vue";

const andco = useAndco();
const accounts = ref<{ id: string; name: string }[]>([]);

async function signIn() {
  await andco.auth.signIn({ scopes: ["openid", "email"] });
}

onMounted(async () => {
  const { data, error } = await andco.rest.http.GET("/accounts");
  if (!error) accounts.value = data.data;
});
</script>
```

## Mostrar un fallo del callback

```ts
onMounted(async () => {
  const { error } = await andco.session.ready;
  if (error) message.value = error.message;
});
```

## Con Nuxt

El provider toca `window`, así que en Nuxt va dentro de `<ClientOnly>`, o bien le entregas la sesión que el servidor ya resolvió para que el primer cuadro sea real:

```vue
<AndcoProvider :client-options="clientOptions" :initial-session="serverSession">
  <NuxtPage />
</AndcoProvider>
```
