mirror of
https://github.com/pretix/pretix.git
synced 2026-08-02 09:27:50 +00:00
preview from server, qrcode in apple event pass
This commit is contained in:
@@ -6,65 +6,53 @@ import Input from "./input/input.vue";
|
||||
import PassPreview from "./preview/pass-preview.vue";
|
||||
import { StoreKey } from "../walletStore";
|
||||
|
||||
const store = inject(StoreKey)!;
|
||||
const gettext = (window as any).gettext;
|
||||
|
||||
const store = inject(StoreKey)!;
|
||||
|
||||
const platformChoices = computed(() => {
|
||||
return [
|
||||
[null, "Do not generate pass"],
|
||||
...Object.values(store.currentPlatformStyles).map((x) => [
|
||||
x.identifier,
|
||||
x.name,
|
||||
]),
|
||||
];
|
||||
});
|
||||
|
||||
function openForm(url: string, data: Record<string, string>) {
|
||||
let form = document.createElement("form");
|
||||
form.target = "_blank";
|
||||
form.method = "POST";
|
||||
form.action = url;
|
||||
form.style.display = "none";
|
||||
let form = document.createElement("form");
|
||||
form.target = "_blank";
|
||||
form.method = "POST";
|
||||
form.action = url;
|
||||
form.style.display = "none";
|
||||
|
||||
for (var key in data) {
|
||||
var input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = data[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.removeChild(form);
|
||||
for (var key in data) {
|
||||
var input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = data[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.removeChild(form);
|
||||
}
|
||||
|
||||
function openPreview(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
openForm("../../preview/", {
|
||||
csrfmiddlewaretoken: store.csrfToken,
|
||||
platform: store.currentPlatform,
|
||||
style: store.currentPlatformLayout.style,
|
||||
layout: JSON.stringify(store.currentPlatformLayout.layout),
|
||||
});
|
||||
e.preventDefault();
|
||||
openForm("../../preview/", {
|
||||
csrfmiddlewaretoken: store.csrfToken,
|
||||
platform: store.currentPlatform,
|
||||
style: store.currentPlatformLayout.style,
|
||||
layout: JSON.stringify(store.currentPlatformLayout.layout),
|
||||
});
|
||||
}
|
||||
|
||||
const preview_layouts = [
|
||||
[
|
||||
{
|
||||
children: [
|
||||
{ fieldgroup: "logo", relSize: 1 },
|
||||
{ fieldgroup: "logo_text", relSize: 3 },
|
||||
{ fieldgroup: "header", relSize: 2 },
|
||||
],
|
||||
},
|
||||
{ fieldgroup: "primary" },
|
||||
{ fieldgroup: "secondary" },
|
||||
{ fieldgroup: "auxiliary" },
|
||||
{ fieldgroup: "code" },
|
||||
],
|
||||
[{ fieldgroup: "back", mode: "column" }],
|
||||
];
|
||||
|
||||
|
||||
const platformChoices = computed(() => {
|
||||
return [
|
||||
[null, "Do not generate pass"],
|
||||
...Object.values(store.currentPlatformStyles).map((x) => [
|
||||
x.identifier,
|
||||
x.name,
|
||||
]),
|
||||
];
|
||||
});
|
||||
|
||||
const preview_layout = computed(() => {
|
||||
return JSON.parse(store.currentPlatformStyles[store.currentPlatformLayout.style].preview_layout)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
@@ -82,23 +70,25 @@ const preview_layouts = [
|
||||
a(role="tab" @click="store.currentPlatform = platform.identifier") {{ platform.name }}
|
||||
.tabbed-form.tab-content
|
||||
.tab-pane.active.row
|
||||
.col-md-8
|
||||
.col-md-6.col-lg-8
|
||||
Select.form-group(label="Style" :modelValue="store.currentPlatformLayout.style" @update:modelValue="store.setCurrentPlatformStyle" :choices="platformChoices")
|
||||
|
||||
StyleSettings(v-if="store.currentPlatformLayout.style" v-model="store.currentPlatformLayout.layout" :style="store.currentPlatformStyles[store.currentPlatformLayout.style]")
|
||||
.col-md-4
|
||||
.col-md-6.col-lg-4
|
||||
.panel.panel-default
|
||||
.panel-heading Preview
|
||||
.panel-body
|
||||
span.text-muted The preview below is only a rough representation of what the pass might look like. Please check the generated pass.
|
||||
PassPreview(v-for="layout in preview_layouts" :layout="layout")
|
||||
|
||||
pre
|
||||
code {{ store.currentPlatformLayout }}
|
||||
pre(v-if="store.currentPlatformLayout.style")
|
||||
code {{ store.currentPlatformStyles[store.currentPlatformLayout.style] }}
|
||||
pre
|
||||
code {{ store.walletLayout }}
|
||||
div(v-if="preview_layout")
|
||||
span.text-muted The preview below is only a rough representation of what the pass might look like. Please check the generated pass.
|
||||
div
|
||||
PassPreview(v-for="layout in preview_layout" :layout="layout")
|
||||
div(v-else) Preview not supported
|
||||
//- pre
|
||||
//- code {{ store.currentPlatformLayout }}
|
||||
//- pre(v-if="store.currentPlatformLayout.style")
|
||||
//- code {{ store.currentPlatformStyles[store.currentPlatformLayout.style] }}
|
||||
//- pre
|
||||
//- code {{ store.walletLayout }}
|
||||
.form-group.submit-group
|
||||
button.btn.btn-lg.btn-default(type="button" @click="openPreview") Preview
|
||||
button.btn.btn-primary.btn-save(type="submit") Submit
|
||||
|
||||
@@ -3,40 +3,42 @@ type BaseFieldGroupDefinition = {
|
||||
identifier: string;
|
||||
name: string;
|
||||
required: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
type FieldGroupDefinition = PlaceholderFieldGroupDefinition | PredefinedFieldGroupDefinition;
|
||||
type FieldGroupDefinition =
|
||||
| PlaceholderFieldGroupDefinition
|
||||
| PredefinedFieldGroupDefinition;
|
||||
|
||||
type FieldGroupDisplay = 'plain' | 'with_label' | 'code';
|
||||
type FieldGroupDisplay = "plain" | "with_label" | "code";
|
||||
|
||||
type PlaceholderFieldGroupDefinition = BaseFieldGroupDefinition & {
|
||||
type: 'placeholder';
|
||||
type: "placeholder";
|
||||
content_type: FieldContentType;
|
||||
default_entries: FieldEntry[];
|
||||
display: FieldGroupDisplay;
|
||||
min_entries: number|null;
|
||||
max_entries: number|null;
|
||||
}
|
||||
min_entries: number | null;
|
||||
max_entries: number | null;
|
||||
};
|
||||
|
||||
type PredefinedFieldGroupDefinition = BaseFieldGroupDefinition & {
|
||||
type: 'predefined';
|
||||
}
|
||||
type: "predefined";
|
||||
};
|
||||
|
||||
type I18nString = string | Record<string, string>
|
||||
type I18nString = null | string | Record<string, string>;
|
||||
|
||||
type FieldContentType = 'text' | 'image';
|
||||
type FieldContentType = "text" | "image";
|
||||
|
||||
type PlaceholderFieldEntry = {
|
||||
type: 'placeholder';
|
||||
label?: I18nString;
|
||||
content?: string;
|
||||
}
|
||||
type: "placeholder";
|
||||
label?: I18nString;
|
||||
content?: string;
|
||||
};
|
||||
|
||||
type CustomFieldEntry = {
|
||||
type: 'custom';
|
||||
label?: I18nString;
|
||||
content?: I18nString;
|
||||
}
|
||||
type: "custom";
|
||||
label?: I18nString;
|
||||
content?: I18nString;
|
||||
};
|
||||
|
||||
type FieldEntry = PlaceholderFieldEntry | CustomFieldEntry;
|
||||
|
||||
@@ -47,7 +49,7 @@ type Style = {
|
||||
};
|
||||
|
||||
type Variable = {
|
||||
label: string
|
||||
label: string;
|
||||
editor_sample: I18nString;
|
||||
};
|
||||
|
||||
@@ -62,7 +64,6 @@ type Variables = Record<string, Variable>;
|
||||
type VariableConfig = Record<string, Variables>;
|
||||
type Platforms = Platform[];
|
||||
|
||||
|
||||
type PlaceholderFieldGroupConfig = {
|
||||
entries: Array<FieldEntry>;
|
||||
overflow: string | null;
|
||||
@@ -70,7 +71,9 @@ type PlaceholderFieldGroupConfig = {
|
||||
|
||||
type PredefinedFieldGroupConfig = {};
|
||||
|
||||
type FieldGroupConfig = PlaceholderFieldGroupConfig | PredefinedFieldGroupConfig;
|
||||
type FieldGroupConfig =
|
||||
| PlaceholderFieldGroupConfig
|
||||
| PredefinedFieldGroupConfig;
|
||||
|
||||
type LayoutData = {
|
||||
fieldgroups: Record<string, FieldGroupConfig>;
|
||||
@@ -85,11 +88,20 @@ type PlatformLayout = {
|
||||
type WalletLayout = {
|
||||
name?: string;
|
||||
platform_layouts: PlatformLayout[];
|
||||
}
|
||||
};
|
||||
type WalletStore = {
|
||||
platforms: Platforms,
|
||||
variables: VariableConfig,
|
||||
locales: Record<string, string>,
|
||||
csrfToken: String,
|
||||
walletLayout: WalletLayout | null
|
||||
}
|
||||
platforms: Platforms;
|
||||
variables: VariableConfig;
|
||||
locales: Record<string, string>;
|
||||
csrfToken: String;
|
||||
walletLayout: WalletLayout | null;
|
||||
};
|
||||
|
||||
type PreviewLayout = Array<PreviewRow>;
|
||||
type PreviewRow = { children: Array<PreviewRow> } | PreviewFieldgroup;
|
||||
type PreviewFieldgroup = {
|
||||
fieldgroup: string;
|
||||
relSize?: number;
|
||||
direction?: 'row' | 'column',
|
||||
display?: Array<string>
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Any
|
||||
|
||||
from .base import (
|
||||
FieldEntryType,
|
||||
FieldGroupDisplay,
|
||||
@@ -268,7 +270,6 @@ class AppleWalletEventTicket(AppleWalletStyle):
|
||||
), # TODO: validation of max field count if combined "Coupons, store cards, and generic passes with a square barcode can have a total of up to four secondary and auxiliary fields, combined."
|
||||
TextFieldGroup(identifier="header", name=_("Header"), max_entries=3),
|
||||
TextFieldGroup(identifier="auxiliary", name=_("Auxiliary"), max_entries=4),
|
||||
TextFieldGroup(identifier="back", name=_("Back")),
|
||||
TextFieldGroup(
|
||||
identifier="code",
|
||||
name=_("QR-Code"),
|
||||
@@ -280,8 +281,9 @@ class AppleWalletEventTicket(AppleWalletStyle):
|
||||
)
|
||||
],
|
||||
),
|
||||
TextFieldGroup(identifier="back", name=_("Back")),
|
||||
]
|
||||
# preview_image = "apple/event_ticket.svg"
|
||||
preview_layout = '[[{"children":[{"fieldgroup":"logo","relSize":1},{"fieldgroup":"logo_text","relSize":3,"display":["bold","large","centered"]},{"fieldgroup":"header","relSize":2,"display":["large", "tight"]}]},{"fieldgroup":"primary","display":"large"},{"fieldgroup":"secondary"},{"fieldgroup":"auxiliary"},{"fieldgroup":"code"}],[{"fieldgroup":"back","direction":"column"}]]'
|
||||
|
||||
def convert_fields(self, strings, fields, prefix):
|
||||
converted = []
|
||||
@@ -300,7 +302,7 @@ class AppleWalletEventTicket(AppleWalletStyle):
|
||||
return converted
|
||||
|
||||
def pass_content(self, fields, strings):
|
||||
content = {
|
||||
content: dict[str, Any] = {
|
||||
"eventTicket": {
|
||||
"primaryFields": self.convert_fields(
|
||||
strings, fields["primary"], "primary"
|
||||
@@ -319,4 +321,12 @@ class AppleWalletEventTicket(AppleWalletStyle):
|
||||
content["logoText"] = self.convert_fields(
|
||||
strings, fields["logo_text"], "logo_text"
|
||||
)[0]["value"]
|
||||
|
||||
if fields['code']:
|
||||
content["barcodes"] = [{
|
||||
"format": "PKBarcodeFormatQR",
|
||||
"message": str(fields["code"][0]["value"]),
|
||||
"messageEncoding": "utf-8",
|
||||
"altText": str(fields["code"][0]["value"])
|
||||
}]
|
||||
return content
|
||||
|
||||
@@ -231,14 +231,15 @@ class PassStyle:
|
||||
name: str
|
||||
# order here limits in what order users can configure field "overspilling" (if too many fields are defined, where should the rest go) -> can only go down in the list
|
||||
# we evaluate the fields in this order, so they overspill in this order as well (fields from primary are appended to the overspilling field before fields from secondary are etc)
|
||||
|
||||
fieldgroups: list[FieldGroup]
|
||||
preview_layout: str | None
|
||||
|
||||
def asdict(self):
|
||||
return {
|
||||
"identifier": self.identifier,
|
||||
"name": self.name,
|
||||
"fieldgroups": [x.asdict() for x in self.fieldgroups],
|
||||
"preview_layout": self.preview_layout
|
||||
}
|
||||
|
||||
def layout_schema(self, context):
|
||||
|
||||
@@ -18,3 +18,4 @@ class GoogleWalletEventTicket(PassStyle):
|
||||
PredefinedFieldGroup(identifier="seating", name=_("Seating")),
|
||||
TextFieldGroup(identifier="qrcode", name=_("QR-Code"), display=FieldGroupDisplay.PLAIN),
|
||||
]
|
||||
preview_layout = None
|
||||
Reference in New Issue
Block a user