diff --git a/src/components/tables/index.ts b/src/components/tables/index.ts index 550d730..0df9ff5 100644 --- a/src/components/tables/index.ts +++ b/src/components/tables/index.ts @@ -4,6 +4,7 @@ import comment from "../../comment"; import type { File, HookFile } from "../../types"; import { parseNameFormats } from "../../utils"; import { mapHookFileToCreateComponent } from "./create"; +import { mapHookFileToUpdateComponent } from "./update"; import { mapHookFileToDeleteComponent } from "./delete"; import { mapHookFileToGetComponent } from "./get"; @@ -17,6 +18,7 @@ export const mapHookFileToComponent = async ( const componentName = fileName.replace("use", ""); const getComponentName = `Get${componentName}`; const createComponentName = `Create${componentName}`; + const updateComponentName = `Update${componentName}`; const deleteComponentName = `Delete${componentName}`; const { camelCasePlural, pascalCase, pascalCasePlural } = parseNameFormats(componentName); @@ -29,15 +31,17 @@ export const mapHookFileToComponent = async ( import ${fileName} from "../../hooks/${fileName}"; import ${getComponentName} from "./${getComponentName}"; import ${createComponentName} from "./${createComponentName}"; + import ${updateComponentName} from "./${updateComponentName}"; import ${deleteComponentName} from "./${deleteComponentName}"; export default function ${componentName}() { - const { ${camelCasePlural}, fetch${pascalCasePlural}, create${pascalCase}, delete${pascalCase} } = ${fileName}(); + const { ${camelCasePlural}, fetch${pascalCasePlural}, create${pascalCase}, update${pascalCase}, delete${pascalCase} } = ${fileName}(); return (
<${getComponentName} ${camelCasePlural}={${camelCasePlural}} onFetch={fetch${pascalCasePlural}} /> <${createComponentName} onCreate={create${pascalCase}} onFetch={fetch${pascalCasePlural}} /> + <${updateComponentName} onUpdate={update${pascalCase}} onFetch={fetch${pascalCasePlural}} /> <${deleteComponentName} onDelete={delete${pascalCase}} onFetch={fetch${pascalCasePlural}} />
) @@ -67,6 +71,9 @@ export const parseComponentFilesForTables = async ( const createComponentPromises = tableHookFiles.map((tableHookFile) => mapHookFileToCreateComponent(tableHookFile, tables) ); + const updateComponentPromises = tableHookFiles.map((tableHookFile) => + mapHookFileToUpdateComponent(tableHookFile, tables) + ); const deleteComponentPromises = tableHookFiles.map((tableHookFile) => mapHookFileToDeleteComponent(tableHookFile, tables) ); @@ -74,6 +81,7 @@ export const parseComponentFilesForTables = async ( const files = await Promise.all([ ...componentPromises, ...createComponentPromises, + ...updateComponentPromises, ...getComponentPromises, ...deleteComponentPromises, ]); diff --git a/src/components/tables/update.ts b/src/components/tables/update.ts new file mode 100644 index 0000000..9b0e50f --- /dev/null +++ b/src/components/tables/update.ts @@ -0,0 +1,208 @@ +import prettier from "prettier"; +import comment from "../../comment"; +import type { ColumnResponse, TablesResponse } from "../../pgMeta/fetchTables"; +import type { File, HookFile } from "../../types"; +import { parseNameFormats } from "../../utils"; + +const mapColumns = ( + columns?: ColumnResponse[] +): { fields: string; inputs: string } => { + if (!columns) { + return { fields: "", inputs: "" }; + } + + const filteredColumns = columns.filter( + (column) => column.isIdentity || column.isUpdatable + ); + const fields = filteredColumns + .filter((column) => !column.isIdentity) + .map((column) => `"${column.name}"`) + .join(","); + const inputs = filteredColumns + .map((column, index) => { + const label = column.isIdentity ? `${column.name}*` : column.name; + return ` +
+ + + 0 ? 'marginTop: "10px",' : ""} + background: "#000", + color: "#fff", + border: "1px solid #34383A", + marginLeft: "10px", + flex: "1", + borderRadius: "0.375rem", + padding: "4px 16px", + }} + /> +
+ `; + }) + .join(" "); + + return { fields, inputs }; +}; + +export const mapHookFileToUpdateComponent = async ( + hookFile: HookFile, + tables: TablesResponse +): Promise => { + const { + entityName, + file: { fileName }, + } = hookFile; + + const table = tables.find((table) => table.name === entityName); + const componentName = `${fileName.replace("use", "")}`; + const { pascalCase } = parseNameFormats(componentName); + + const { fields, inputs } = mapColumns(table?.columns); + + const content = ` + ${comment} + + "use client"; + + import { FormEventHandler, MouseEventHandler, useState } from "react"; + import type { Row, Update${pascalCase} } from "../../hooks/${fileName}"; + + const fields: Array = [${fields}] + + export default function Update${componentName}({ + onUpdate, + onFetch + }: { + onUpdate: (id: Row["id"], updatedRow: Update${pascalCase}) => Promise, + onFetch: () => Promise + }) { + const [message, setMessage] = useState(); + + const handleSubmit: FormEventHandler = (event) => { + event.preventDefault(); + const target = event.target as typeof event.target & Update${pascalCase}; + const id = (target["id"] as any)?.value; + const updatedRow = fields + .map((field) => ({ field, value: (target[field] as any)?.value })) + .reduce((newRow, { field,value }) => { + if (value.trim() !== "") { + newRow[field] = value; + } + return newRow; + }, {} as Record); + onUpdate(id, updatedRow) + .then((task) => { + if (task) { + setMessage("row with id " + task.id + " updated!"); + onFetch(); + } else { + setMessage("failed to update row!"); + } + }) + .catch((error) => { + if (error.message) { + setMessage(error.message); + } else { + setMessage("failed to update row!"); + } + }); + }; + + const handleClick: MouseEventHandler = () => { + setMessage(undefined); + } + + if (message) { + return
+ {message} + +
+ } + + return ( +
+
+ ${inputs} + +
+
+ ); + } + `; + + const formattedContent = await prettier.format(content, { + parser: "typescript", + }); + + return { + fileName: `Update${componentName}.tsx`, + content: formattedContent, + }; +}; diff --git a/src/hooks/table.ts b/src/hooks/table.ts index 79fdf68..0daae99 100644 --- a/src/hooks/table.ts +++ b/src/hooks/table.ts @@ -29,17 +29,17 @@ const mapTableToFile = async (table: TableResponse): Promise => { }, []); const fetch${pascalCasePlural} = async() => { - try { - const { data, error } = await supabase - .from("${tableName}") - .select(); - if (error) { - throw error; - } - set${pascalCasePlural}(data || []); - } catch (error) { - console.error("Error fetching", error); + try { + const { data, error } = await supabase + .from("${tableName}") + .select(); + if (error) { + throw error; } + set${pascalCasePlural}(data || []); + } catch (error) { + console.error("Error fetching", error); + } }; const create${pascalCase} = async (newData: Insert${pascalCase}) => { @@ -55,23 +55,20 @@ const mapTableToFile = async (table: TableResponse): Promise => { }; const update${pascalCase} = async (id: Row["id"], updatedData: Update${pascalCase}) => { - try { - const { data, error } = await supabase - .from("${tableName}") - .update(updatedData) - .eq("id", id) - .select(); - if (error) { - throw error; - } - set${pascalCasePlural}( - ${camelCasePlural}.map((${camelCase}) => - ${camelCase}.id === id ? { ...${camelCase}, ...data[0] } : ${camelCase} - ) - ); - } catch (error) { - console.error("Error updating alert:", error); + const { data, error } = await supabase + .from("${tableName}") + .update(updatedData) + .eq("id", id) + .select(); + if (error) { + throw error; } + set${pascalCasePlural}( + ${camelCasePlural}.map((${camelCase}) => + ${camelCase}.id === id ? { ...${camelCase}, ...data[0] } : ${camelCase} + ) + ); + return data[0]; }; const delete${pascalCase} = async (id: Row["id"]): Promise => {