// deno-lint-ignore-file no-explicit-any
import { Reload } from "@islands/utils/reload.tsx";
type valid_value_types = string | boolean | number | Date | valid_value_types[]
interface PostifyError {
data?: Record<string, any>
message: string
error: Error
}
type PostifyCallback<T extends Record<string, any> = Record<string, any>> = (error: PostifyError | null, response: T | null, extras: PostifyCallbackExtras) => void;
interface PostifyCallbackExtras {
reload: () => void
reset_form: () => void
}
interface PostifyOptions {
callback?: PostifyCallback | null
overrides?: Record<string, any>
}
function PostifyResetForm(this: HTMLFormElement) {
this.reset();
}
export const Postify = ({ callback, overrides = {} }: PostifyOptions = {}) => async (e: SubmitEvent) => {
e.preventDefault();
e.stopPropagation();
const form = e.target as HTMLFormElement;
const data: Record<string, valid_value_types> = {};
const input_elements = form.querySelectorAll<HTMLInputElement>('input[name]');
for(const input of input_elements as any) {
const name = input.name as string;
let value: string | number | boolean | Date;
switch(input.type) {
case 'number': {
value = parseFloat(input.value);
break;
}
case 'checkbox': {
value = input.checked;
break;
}
case 'date': {
value = new Date(input.value);
break;
}
default: {
value = input.value;
}
}
if(data[name] === undefined) {
data[name] = value;
} else {
data[name] = [data[name], value].flat();
}
}
for(const [key, value] of Object.entries(overrides)) {
data[key] = value;
}
const result = await fetch(form.action, {
method: 'POST',
body: JSON.stringify(data)
});
const extras: PostifyCallbackExtras = {
reload: Reload,
reset_form: PostifyResetForm.bind(form),
}
let json: Record<string, any> = {};
const text = await result.text();
try {
json = JSON.parse(text);
} catch(_) {/* */}
if(!result.ok) return callback?.({message: json?.message || json?.reason || text || 'Unspecified error', error: new Error(`${result.statusText}\n${text}`)}, null, extras);
try {
callback?.(null, json, extras);
} catch(e: any) {
callback?.({message: e.message, error: new Error(`Could not parse response json. [${e.message}]`)}, null, extras);
}
return false;
}