Consume form submission

This commit is contained in:
Ondřej 2024-02-03 22:00:42 +01:00
parent 190807801f
commit 9e37ffcaba
9 changed files with 266 additions and 19 deletions

View file

@ -1,8 +1,13 @@
import { defineConfig } from 'astro/config'; import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind"; import tailwind from "@astrojs/tailwind";
import node from "@astrojs/node";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [tailwind()] output: "hybrid",
integrations: [tailwind()],
adapter: node({
mode: "standalone"
})
}); });

174
package-lock.json generated
View file

@ -9,10 +9,12 @@
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@astrojs/check": "^0.4.1", "@astrojs/check": "^0.4.1",
"@astrojs/node": "^8.2.0",
"@astrojs/tailwind": "^5.1.0", "@astrojs/tailwind": "^5.1.0",
"astro": "^4.3.2", "astro": "^4.3.2",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5.3.3" "typescript": "^5.3.3",
"zod": "^3.22.4"
} }
}, },
"node_modules/@alloc/quick-lru": { "node_modules/@alloc/quick-lru": {
@ -127,6 +129,18 @@
"vfile": "^6.0.1" "vfile": "^6.0.1"
} }
}, },
"node_modules/@astrojs/node": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-8.2.0.tgz",
"integrity": "sha512-keQIPvdx8hquG+KnWoJp7io/GoczBEJer9X8WzPHK2fnVRXYDKGzXWZw3Dbg0ZhXJreVV3xzniN7nr6e7hgDXg==",
"dependencies": {
"send": "^0.18.0",
"server-destroy": "^1.0.1"
},
"peerDependencies": {
"astro": "^4.2.0"
}
},
"node_modules/@astrojs/prism": { "node_modules/@astrojs/prism": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.0.0.tgz",
@ -2217,6 +2231,14 @@
"node": ">=4.0.0" "node": ">=4.0.0"
} }
}, },
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/dequal": { "node_modules/dequal": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -2225,6 +2247,15 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
@ -2293,6 +2324,11 @@
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
}, },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.656", "version": "1.4.656",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.656.tgz",
@ -2312,6 +2348,14 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==" "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
}, },
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/end-of-stream": { "node_modules/end-of-stream": {
"version": "1.4.4", "version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -2382,6 +2426,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"node_modules/escape-string-regexp": { "node_modules/escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -2410,6 +2459,14 @@
"@types/estree": "^1.0.0" "@types/estree": "^1.0.0"
} }
}, },
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
@ -2561,6 +2618,14 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fs-constants": { "node_modules/fs-constants": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@ -2895,6 +2960,21 @@
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
}, },
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/human-signals": { "node_modules/human-signals": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
@ -4364,6 +4444,17 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/once": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -5020,6 +5111,14 @@
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
"optional": true "optional": true
}, },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/rc": { "node_modules/rc": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@ -5761,11 +5860,68 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}, },
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/send/node_modules/debug/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/send/node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/server-destroy": { "node_modules/server-destroy": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
"integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==" "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ=="
}, },
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/sharp": { "node_modules/sharp": {
"version": "0.32.6", "version": "0.32.6",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz",
@ -5913,6 +6069,14 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
}, },
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/stdin-discarder": { "node_modules/stdin-discarder": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz",
@ -6261,6 +6425,14 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/trim-lines": { "node_modules/trim-lines": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",

View file

@ -11,9 +11,11 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.4.1", "@astrojs/check": "^0.4.1",
"@astrojs/node": "^8.2.0",
"@astrojs/tailwind": "^5.1.0", "@astrojs/tailwind": "^5.1.0",
"astro": "^4.3.2", "astro": "^4.3.2",
"tailwindcss": "^3.4.1", "tailwindcss": "^3.4.1",
"typescript": "^5.3.3" "typescript": "^5.3.3",
"zod": "^3.22.4"
} }
} }

View file

@ -17,22 +17,20 @@ const { lang, options = {} } = Astro.props;
const result = letterOptionsSchema.safeParse(options); const result = letterOptionsSchema.safeParse(options);
--- ---
<form id="body-form" action={`/${lang}/send`} method="post" hx-include="#options-form"> <form id="body-form" action={`/${lang}`} method="post" hx-include="#options-form [name]">
<div class="mb-6"> <div class="mb-6">
<label class="block text-base mb-2" for="letter-input"> <label class="block text-base mb-2" for="letter-input">
{t("form.letter")} {t("form.letter")}
</label> </label>
<div class="relative overflow-hidden rounded-[3px]"> <div class="relative overflow-hidden rounded-[3px]">
<textarea <textarea
name="letter_body" name="letterBody"
id="letter-input" id="letter-input"
cols={60} cols={60}
rows={20} rows={20}
class="block w-full px-4 py-3 bg-white text-black text-lg" class="block w-full px-4 py-3 bg-white text-black text-lg"
style="white-space: pre-wrap" style="white-space: pre-wrap">{renderText(lang, options)}</textarea
> >
{renderText(lang, options)}
</textarea>
{ {
!result.success && ( !result.success && (
<div class="absolute inset-0 grid place-content-center bg-white/75 text-black"> <div class="absolute inset-0 grid place-content-center bg-white/75 text-black">

View file

@ -5,8 +5,13 @@ import RadioGroup from "../ui/RadioGroup.astro";
import { t } from "../i18n"; import { t } from "../i18n";
import Label from "../ui/Label.astro"; import Label from "../ui/Label.astro";
import Select from "../ui/Select.astro"; import Select from "../ui/Select.astro";
import type { Lang } from "../lang";
const lang: string = ""; interface Props {
lang: Lang;
}
const { lang } = Astro.props;
interface Branch { interface Branch {
id: number; id: number;
@ -28,8 +33,8 @@ const branches: Array<Branch> = [
class="grid gap-8 mb-12" class="grid gap-8 mb-12"
novalidate novalidate
> >
<Field required label={t("form.first_name")} name="firstname" /> <Field required label={t("form.first_name")} name="firstName" />
<Field required label={t("form.last_name")} name="lastname" /> <Field required label={t("form.last_name")} name="lastName" />
<RadioGroup required label={t("form.variant")}> <RadioGroup required label={t("form.variant")}>
<Radio name="variant" value="1" label={t("form.variant.1")} checked /> <Radio name="variant" value="1" label={t("form.variant.1")} checked />
<Radio name="variant" value="2" label={t("form.variant.2")} /> <Radio name="variant" value="2" label={t("form.variant.2")} />

View file

@ -4,14 +4,40 @@ import { t } from "../../i18n";
import Layout from "../../layouts/Layout.astro"; import Layout from "../../layouts/Layout.astro";
import LetterBodyForm from "../../letter/LetterBodyForm.astro"; import LetterBodyForm from "../../letter/LetterBodyForm.astro";
import LetterOptionsForm from "../../letter/LetterOptionsForm.astro"; import LetterOptionsForm from "../../letter/LetterOptionsForm.astro";
import { z } from "zod";
export function getStaticPaths() { export { getStaticPaths } from "../../static-paths";
return LANGUAGES.map((lang) => ({
params: { lang },
}));
}
const { lang } = Astro.params; const { lang } = Astro.params;
if (Astro.request.method === "POST") {
const formSchema = z.object({
firstName: z.string().min(1),
lastName: z.string().min(1),
variant: z.string().default("1"),
gender: z.string().default("g"),
letterBody: z.string().min(1),
email: z.string().min(1),
});
const formData = await Astro.request.formData();
const data = Object.fromEntries(formData.entries());
const result = await formSchema.safeParseAsync(data);
if (result.success) {
// TODO persist
console.log(result.data);
return Astro.redirect(`/${lang}/letter-sent`, 303);
}
console.error(result.error.message);
// No need to elaborate, validation feedback should be provided by
// client side validation.
Astro.response.status = 403;
Astro.response.statusText = "Forbidden";
}
--- ---
<Layout> <Layout>
@ -36,7 +62,7 @@ const { lang } = Astro.params;
Napiš pojišťovnám, ať přestanou podporovat fosilní byznys. Napiš pojišťovnám, ať přestanou podporovat fosilní byznys.
</p> </p>
</header> </header>
<div class="grid lg:grid-cols-3 items-start gap-12"> <div class="grid lg:grid-cols-3 items-start gap-12" id="letter-form">
<LetterOptionsForm lang={lang} /> <LetterOptionsForm lang={lang} />
<div class="lg:col-span-2"> <div class="lg:col-span-2">
<LetterBodyForm lang={lang} /> <LetterBodyForm lang={lang} />

View file

@ -0,0 +1,9 @@
---
import Layout from "../../layouts/Layout.astro";
export { getStaticPaths } from "../../static-paths";
---
<Layout>
<div class="max-w-screen-xl px-6 mx-auto">Success</div>
</Layout>

View file

@ -0,0 +1,23 @@
---
import type { Lang } from "../../lang";
import LetterBodyForm from "../../letter/LetterBodyForm.astro";
import type { LetterOptions } from "../../letter/templates";
export const prerender = false;
export const partial = true;
interface Params {
lang: Lang;
}
const { lang } = Astro.params as unknown as Params;
const params = Astro.url.searchParams;
const options: Partial<LetterOptions> = {
firstName: params.get("firstName") ?? undefined,
lastName: params.get("lastName") ?? undefined,
variant: params.get("variant") ?? undefined,
gender: params.get("gender") ?? undefined,
};
---
<LetterBodyForm lang={lang} options={options} />

7
src/static-paths.ts Normal file
View file

@ -0,0 +1,7 @@
import { LANGUAGES } from "./config";
export function getStaticPaths() {
return LANGUAGES.map((lang) => ({
params: { lang },
}));
}