diff --git a/app/components/Admin/ModalForm.vue b/app/components/Admin/ModalForm.vue index 9809aaa..daa7186 100644 --- a/app/components/Admin/ModalForm.vue +++ b/app/components/Admin/ModalForm.vue @@ -27,16 +27,34 @@ interface ModalFormProps { item?: T fields: Field[] title?: string + onSave: (value: any) => Promise } const props = defineProps>() const open = defineModel("open", { required: true }) -const emit = defineEmits<{ (e: "save", value: any): boolean }>() let localItem = reactive({}) -const save = () => { - if (emit("save", localItem)) open.value = false +watch( + () => props.item, + (item) => { + Object.keys(localItem).forEach((k) => delete localItem[k]) + + if (!item) return + + for (const [key, value] of Object.entries(item)) { + localItem[key] = value + } + + for (const field of props.fields) { + if (field.type == "file") localItem[field.key as string] = null + } + }, + { immediate: true }, +) + +const save = async () => { + if (await props.onSave(localItem)) open.value = false } diff --git a/app/pages/admin/artists.vue b/app/pages/admin/artists.vue index cc340bc..dba835b 100644 --- a/app/pages/admin/artists.vue +++ b/app/pages/admin/artists.vue @@ -1 +1,131 @@ - + + + + + diff --git a/app/ui/Table.vue b/app/ui/Table.vue index b54c201..94f7d0e 100644 --- a/app/ui/Table.vue +++ b/app/ui/Table.vue @@ -4,6 +4,7 @@ export type Row = { class?: string width?: string type?: "image" + imagePrefix?: string displayName?: string } @@ -34,6 +35,10 @@ const { rows, data } = defineProps()

{{ item[row.name] }}

+
@@ -63,5 +68,10 @@ const { rows, data } = defineProps() & thead { } + + & img { + height: 60px; + border-radius: $border-radius-standard; + } } diff --git a/app/utils/cfetch.ts b/app/utils/cfetch.ts index f5d9245..e542bfb 100644 --- a/app/utils/cfetch.ts +++ b/app/utils/cfetch.ts @@ -1,10 +1,25 @@ import axios, { type AxiosRequestConfig, type AxiosResponse } from "axios" import defu from "defu" +const hasFile = (value: any): boolean => { + if (!value || typeof value !== "object") return false + + return Object.values(value).some( + (v) => + v instanceof File || + v instanceof Blob || + (Array.isArray(v) && v.some((i) => i instanceof File)), + ) +} + +type RequestConfig = { + forceFormData?: boolean +} & AxiosRequestConfig + export const cfetch = async ( url: string, - options: AxiosRequestConfig = {}, - authorize: boolean = true + options: RequestConfig = {}, + authorize: boolean = true, ): Promise => { const baseUrl = import.meta.env.VITE_PUBLIC_BACKEND @@ -26,7 +41,24 @@ export const cfetch = async ( } } - const config: AxiosRequestConfig = defu(options, defaults) + const config: RequestConfig = defu(options, defaults) + + if (config.data && (hasFile(config.data) || config.forceFormData)) { + const form = new FormData() + + for (const [key, val] of Object.entries(config.data)) { + if (Array.isArray(val)) { + val.forEach((v) => form.append(`${key}[]`, v)) + } else if (val !== undefined && val !== null) { + form.append(key, val as any) + } + } + + config.data = form + + if (!config.headers) config.headers = {} + delete config.headers["Content-Type"] + } let response try {