@seatsyoo/vue 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -240,7 +240,43 @@ hidrata y monta el visor. En Nuxt funciona tal cual (también dentro de `<Client
240
240
  No va en el paquete: el visor la descarga de `${server}/sdk/butacas-3d.js` cuando alguien la abre. Si tu web
241
241
  tiene una política de seguridad de contenidos (CSP), añade esa dirección a `script-src`, o pasa `:view3d="false"`.
242
242
 
243
- La referencia completa de opciones, avisos y métodos está en la documentación de Seatsyoo (**/docs/visor** y
243
+ ## El diseñador de planos
244
+
245
+ `<SeatsyooDesigner>` abre en tu web el diseñador de planos de Seatsyoo, para que tus clientes dibujen sus recintos.
246
+ Tu servidor abre una sesión para un plano con su clave secreta (`POST /api/v1/charts/{plano}/designer-sessions`, o
247
+ `charts.designerSession` de `@seatsyoo/node`) y le da el token a tu web:
248
+
249
+ ```vue
250
+ <script setup lang="ts">
251
+ import { SeatsyooDesigner } from "@seatsyoo/vue";
252
+
253
+ defineProps<{ token: string }>();
254
+ const emit = defineEmits<{ cerrar: [] }>();
255
+ // Tu servidor abre otra sesión del mismo plano y te da el token (aquí, una ruta tuya).
256
+ const pedirToken = (): Promise<string> =>
257
+ fetch("/mi-api/disenador/teatro", { method: "POST" }).then((r) => r.json()).then((s: { token: string }) => s.token);
258
+ </script>
259
+
260
+ <template>
261
+ <SeatsyooDesigner
262
+ server="https://seatsyoo.example"
263
+ :token="token"
264
+ :refresh-token="pedirToken"
265
+ style="height: 80vh"
266
+ @publish="({ version }) => console.log('Publicada la versión', version)"
267
+ @close="emit('cerrar')"
268
+ />
269
+ </template>
270
+ ```
271
+
272
+ Props: `server`, `token`, `language` y `refreshToken` (pide a tu servidor otro token del mismo plano antes de que
273
+ caduque: sin ella, al caducar deja de guardar). Eventos: `ready`, `save`, `publish`, `close` («←» sale si hay quien
274
+ escuche `@close` al montarse) y `error`. `class`, `style` e `id` van al `<div>`, que necesita alto. Un `token` nuevo se le
275
+ manda sin volver a montarlo; cambiar `server` o `language`, o pasar o quitar `refreshToken`, lo vuelve a montar. Con
276
+ una ref de plantilla, `disenador.value.designer` es el diseñador (`setToken()`, `iframe`). `app.use(SeatsyooPlugin)`
277
+ también lo registra. En el servidor (SSR) pinta solo el `<div>`.
278
+
279
+ La referencia completa de opciones, avisos y métodos está en la documentación de Seatsyoo (**/docs/visor**, **/docs/disenador** y
244
280
  **/docs/frameworks**).
245
281
 
246
282
  ## Licencia
@@ -273,6 +309,9 @@ npm install @seatsyoo/vue
273
309
  (never the selected keys). -->
274
310
  ```
275
311
 
312
+ - **Embedded designer**: `<SeatsyooDesigner server :token :refresh-token @publish @close style="height: 80vh" />` opens
313
+ the Seatsyoo chart designer in your website, with a session token your server opens with its secret key
314
+ (`POST /api/v1/charts/{chart}/designer-sessions`).
276
315
  - **Props**: every viewer option except `container` and the callbacks; `class`, `style`, `id` and other attributes
277
316
  go to the wrapping `<div>`. `app.use(SeatsyooPlugin)` registers `<SeatsyooChart>` globally.
278
317
  - **Events**: `ready`, `change`, `select`, `deselect`, `error`, `hold-expired`, `hold-token-change`,
@@ -1,5 +1,6 @@
1
1
  import { type ChartDocument, type Language, type SeatingChart, type SelectedObject, type StatusStyle, type View3DModule } from "@seatsyoo/visor";
2
2
  import { type ComponentOptionsMixin, type DefineComponent, type ExtractPublicPropTypes, type Plugin, type PropType } from "vue";
3
+ import { SeatsyooDesigner } from "./SeatsyooDesigner.js";
3
4
  declare const props: {
4
5
  /** URL base del servidor de Seatsyoo, p. ej. https://seatsyoo.example */
5
6
  server: {
@@ -139,12 +140,14 @@ export type SeatsyooChartComponent = DefineComponent<typeof props, SeatsyooChart
139
140
  * mientras no hay ninguno.
140
141
  */
141
142
  export declare const SeatsyooChart: SeatsyooChartComponent;
142
- /** Plugin que registra <SeatsyooChart> en toda la aplicación: `app.use(SeatsyooPlugin)`. */
143
+ /** Plugin que registra <SeatsyooChart> y <SeatsyooDesigner> en toda la aplicación: `app.use(SeatsyooPlugin)`. */
143
144
  export declare const SeatsyooPlugin: Plugin;
144
145
  declare module "vue" {
145
146
  interface GlobalComponents {
146
147
  /** El visor de Seatsyoo (registrado con `app.use(SeatsyooPlugin)`). */
147
148
  SeatsyooChart: typeof SeatsyooChart;
149
+ /** El diseñador de planos de Seatsyoo (registrado con `app.use(SeatsyooPlugin)`). */
150
+ SeatsyooDesigner: typeof SeatsyooDesigner;
148
151
  }
149
152
  }
150
153
  export {};
@@ -11,6 +11,7 @@
11
11
  // ese momento, sin volver a montar.
12
12
  import { render, } from "@seatsyoo/visor";
13
13
  import { defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, shallowRef, toRaw, watch, } from "vue";
14
+ import { SeatsyooDesigner } from "./SeatsyooDesigner.js";
14
15
  import { aplicarEnVivo, avisarEnConsola, copiaDeDatos, enVivoDe, errorDeOpciones, identidadDe, igual, opcionesEnVivo, sinIndefinidos, sueltaAlCambiar, } from "./opciones.js";
15
16
  // Los booleanos con `default: undefined`: sin él, Vue los pone a false si no se pasan, y el visor los quiere
16
17
  // sin indicar (su valor por defecto es «sí»).
@@ -216,9 +217,10 @@ const componente = defineComponent({
216
217
  * mientras no hay ninguno.
217
218
  */
218
219
  export const SeatsyooChart = componente;
219
- /** Plugin que registra <SeatsyooChart> en toda la aplicación: `app.use(SeatsyooPlugin)`. */
220
+ /** Plugin que registra <SeatsyooChart> y <SeatsyooDesigner> en toda la aplicación: `app.use(SeatsyooPlugin)`. */
220
221
  export const SeatsyooPlugin = {
221
222
  install(app) {
222
223
  app.component("SeatsyooChart", SeatsyooChart);
224
+ app.component("SeatsyooDesigner", SeatsyooDesigner);
223
225
  },
224
226
  };
@@ -0,0 +1,71 @@
1
+ import { type EmbeddedDesigner, type Language } from "@seatsyoo/visor";
2
+ import { type ComponentOptionsMixin, type DefineComponent, type ExtractPublicPropTypes, type PropType } from "vue";
3
+ type Estado = "draft" | "published" | "published-with-draft";
4
+ declare const props: {
5
+ /** URL base del servidor de Seatsyoo, p. ej. https://seatsyoo.example */
6
+ server: {
7
+ type: StringConstructor;
8
+ required: true;
9
+ };
10
+ /** El token de la sesión del diseñador (dsg_…), que abre tu servidor con su clave secreta. */
11
+ token: {
12
+ type: StringConstructor;
13
+ required: true;
14
+ };
15
+ /** Idioma del diseñador: «es» (por defecto) o «en». */
16
+ language: PropType<Language>;
17
+ /** Pide a tu servidor otro token del mismo plano antes de que caduque (sin ella, al caducar deja de guardar). */
18
+ refreshToken: PropType<() => Promise<string>>;
19
+ };
20
+ declare const emits: {
21
+ /** El diseñador está abierto con el plano. */
22
+ ready: (info: {
23
+ chart: string;
24
+ status: Estado;
25
+ publishedVersion: number | null;
26
+ canPublish: boolean;
27
+ }) => boolean;
28
+ /** Se han guardado los cambios en el borrador. */
29
+ save: (info: {
30
+ chart: string;
31
+ status: Estado;
32
+ }) => boolean;
33
+ /** Se ha publicado una versión nueva. */
34
+ publish: (info: {
35
+ chart: string;
36
+ version: number;
37
+ }) => boolean;
38
+ /** Se ha pulsado «←» (sale solo si hay quien escuche @close al montarse). */
39
+ close: () => boolean;
40
+ /** Algo ha fallado: `{ code, message }`. Sin oyente, se escribe en la consola. */
41
+ error: (error: {
42
+ code: string;
43
+ message: string;
44
+ }) => boolean;
45
+ };
46
+ /** Props de SeatsyooDesigner: las opciones del diseñador, sin `container` ni los avisos (que son eventos). */
47
+ export type SeatsyooDesignerProps = ExtractPublicPropTypes<typeof props>;
48
+ /** Lo que expone el componente a una ref de plantilla. */
49
+ export interface SeatsyooDesignerExposed {
50
+ /** El diseñador abierto (`setToken()`, `iframe`), o null mientras no hay ninguno. */
51
+ designer: EmbeddedDesigner | null;
52
+ }
53
+ /** Su tipo público, escrito a mano como el de SeatsyooChart (con los parámetros que no han cambiado desde Vue 3.3). */
54
+ export type SeatsyooDesignerComponent = DefineComponent<typeof props, SeatsyooDesignerExposed, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, typeof emits>;
55
+ /**
56
+ * El diseñador de planos de Seatsyoo en tu web, con el token de una sesión que abre tu servidor con su clave secreta
57
+ * (`POST /api/v1/charts/{plano}/designer-sessions`, o `charts.designerSession` de `@seatsyoo/node`).
58
+ *
59
+ * ```vue
60
+ * <SeatsyooDesigner
61
+ * server="https://seatsyoo.example"
62
+ * :token="token"
63
+ * :refresh-token="pedirToken"
64
+ * style="height: 80vh"
65
+ * @publish="({ version }) => console.log(version)"
66
+ * @close="abierto = false"
67
+ * />
68
+ * ```
69
+ */
70
+ export declare const SeatsyooDesigner: SeatsyooDesignerComponent;
71
+ export {};
@@ -0,0 +1,138 @@
1
+ // SeatsyooDesigner: el diseñador de planos de Seatsyoo, incrustado en tu web, como componente de Vue 3 (3.3 o posterior),
2
+ // sin SFC (defineComponent y una función render), como SeatsyooChart.
3
+ //
4
+ // - Se monta en onMounted: en el servidor (SSR) solo se pinta el <div> vacío. Antes de desmontar, destroy().
5
+ // - Vuelve a montarse si cambia `server` o `language`, o si se pasa o se quita `refreshToken`: la página del diseñador
6
+ // sabe al abrirse si puede pedir tokens nuevos. «←» sale si al montarse hay quien escuche @close.
7
+ // - Un `token` nuevo con el diseñador abierto no lo vuelve a montar: se le manda (setToken), como al renovarlo.
8
+ // - Los avisos salen como eventos de Vue (ready, save, publish, close, error); refreshToken es una prop (devuelve el
9
+ // token) y se llama siempre la última recibida.
10
+ import { designer } from "@seatsyoo/visor";
11
+ import { defineComponent, getCurrentInstance, h, onBeforeUnmount, onMounted, shallowRef, watch, } from "vue";
12
+ import { avisarEnConsola, errorDeOpciones } from "./opciones.js";
13
+ const props = {
14
+ /** URL base del servidor de Seatsyoo, p. ej. https://seatsyoo.example */
15
+ server: { type: String, required: true },
16
+ /** El token de la sesión del diseñador (dsg_…), que abre tu servidor con su clave secreta. */
17
+ token: { type: String, required: true },
18
+ /** Idioma del diseñador: «es» (por defecto) o «en». */
19
+ language: String,
20
+ /** Pide a tu servidor otro token del mismo plano antes de que caduque (sin ella, al caducar deja de guardar). */
21
+ refreshToken: Function,
22
+ };
23
+ // Los parámetros solo dan el tipo de cada evento (Vue valida con lo que devuelven: siempre sí).
24
+ const emits = {
25
+ /** El diseñador está abierto con el plano. */
26
+ ready: (info) => true,
27
+ /** Se han guardado los cambios en el borrador. */
28
+ save: (info) => true,
29
+ /** Se ha publicado una versión nueva. */
30
+ publish: (info) => true,
31
+ /** Se ha pulsado «←» (sale solo si hay quien escuche @close al montarse). */
32
+ close: () => true,
33
+ /** Algo ha fallado: `{ code, message }`. Sin oyente, se escribe en la consola. */
34
+ error: (error) => true,
35
+ };
36
+ const componente = defineComponent({
37
+ name: "SeatsyooDesigner",
38
+ props,
39
+ emits,
40
+ expose: ["designer"],
41
+ setup(props, { emit }) {
42
+ const abierto = shallowRef(null);
43
+ const el = shallowRef(null);
44
+ const instancia = getCurrentInstance();
45
+ let vivo = false;
46
+ /** El último token que se le dio al diseñador abierto. */
47
+ let token = "";
48
+ /** ¿Hay alguien escuchando ese evento ahora mismo? */
49
+ function escuchan(evento) {
50
+ const p = instancia?.vnode.props;
51
+ const f = p?.[evento] ?? p?.[`${evento}Once`];
52
+ return typeof f === "function" || Array.isArray(f);
53
+ }
54
+ function desmontar() {
55
+ const anterior = abierto.value;
56
+ abierto.value = null;
57
+ anterior?.destroy();
58
+ }
59
+ function montar() {
60
+ desmontar();
61
+ const div = el.value;
62
+ if (!div)
63
+ return;
64
+ const refresh = props.refreshToken;
65
+ try {
66
+ abierto.value = designer({
67
+ container: div,
68
+ server: props.server,
69
+ token: props.token,
70
+ ...(props.language ? { language: props.language } : {}),
71
+ ...(refresh ? { refreshToken: () => (props.refreshToken ?? refresh)() } : {}),
72
+ ...(escuchan("onClose") ? { onClose: () => emit("close") } : {}),
73
+ onReady: (i) => emit("ready", i),
74
+ onSave: (i) => emit("save", i),
75
+ onPublish: (i) => emit("publish", i),
76
+ onError: (e) => (escuchan("onError") ? emit("error", e) : avisarEnConsola(e)),
77
+ });
78
+ token = props.token;
79
+ }
80
+ catch (err) {
81
+ const error = errorDeOpciones(err);
82
+ if (escuchan("onError"))
83
+ emit("error", error);
84
+ else
85
+ console.error("[seatsyoo]", error.message);
86
+ }
87
+ }
88
+ onMounted(() => {
89
+ vivo = true;
90
+ montar();
91
+ });
92
+ onBeforeUnmount(() => {
93
+ vivo = false;
94
+ desmontar();
95
+ });
96
+ watch(() => [props.server, props.language, !!props.refreshToken], () => {
97
+ if (vivo)
98
+ montar();
99
+ });
100
+ watch(() => props.token, (nuevo) => {
101
+ const d = abierto.value;
102
+ if (!vivo || !d || nuevo === token)
103
+ return;
104
+ try {
105
+ d.setToken(nuevo);
106
+ token = nuevo;
107
+ }
108
+ catch (err) {
109
+ const error = errorDeOpciones(err);
110
+ if (escuchan("onError"))
111
+ emit("error", error);
112
+ else
113
+ avisarEnConsola(error);
114
+ }
115
+ });
116
+ return { designer: abierto, el };
117
+ },
118
+ render() {
119
+ // class, style, id y demás atributos pasan solos a este <div> (inheritAttrs).
120
+ return h("div", { ref: "el" });
121
+ },
122
+ });
123
+ /**
124
+ * El diseñador de planos de Seatsyoo en tu web, con el token de una sesión que abre tu servidor con su clave secreta
125
+ * (`POST /api/v1/charts/{plano}/designer-sessions`, o `charts.designerSession` de `@seatsyoo/node`).
126
+ *
127
+ * ```vue
128
+ * <SeatsyooDesigner
129
+ * server="https://seatsyoo.example"
130
+ * :token="token"
131
+ * :refresh-token="pedirToken"
132
+ * style="height: 80vh"
133
+ * @publish="({ version }) => console.log(version)"
134
+ * @close="abierto = false"
135
+ * />
136
+ * ```
137
+ */
138
+ export const SeatsyooDesigner = componente;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { SeatsyooChart, type SeatsyooChartExposed, type SeatsyooChartProps, SeatsyooPlugin } from "./SeatsyooChart.js";
2
- export type { ChartDocument, Language, RenderOptions, SeatingChart, SelectedObject, StatusStyle } from "@seatsyoo/visor";
2
+ export { SeatsyooDesigner, type SeatsyooDesignerExposed, type SeatsyooDesignerProps } from "./SeatsyooDesigner.js";
3
+ export type { ChartDocument, EmbeddedDesigner, EmbeddedDesignerOptions, Language, RenderOptions, SeatingChart, SelectedObject, StatusStyle, } from "@seatsyoo/visor";
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- // @seatsyoo/vue: el visor de mapas de asientos de Seatsyoo como componente de Vue 3.
1
+ // @seatsyoo/vue: el visor de mapas de asientos de Seatsyoo y su diseñador de planos como componentes de Vue 3.
2
2
  export { SeatsyooChart, SeatsyooPlugin } from "./SeatsyooChart.js";
3
+ export { SeatsyooDesigner } from "./SeatsyooDesigner.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seatsyoo/vue",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Componente de Vue para el visor de mapas de asientos de Seatsyoo: elegir butacas, retenerlas y venderlas en tiempo real.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -27,7 +27,7 @@
27
27
  "dist/*.d.ts"
28
28
  ],
29
29
  "dependencies": {
30
- "@seatsyoo/visor": "^1.0.0"
30
+ "@seatsyoo/visor": "^1.1.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "vue": "^3.3.0"