From 74c3933ff89a1c3377133eedb74cc6550d337280 Mon Sep 17 00:00:00 2001 From: HungLV Date: Fri, 16 Aug 2024 08:36:17 +0700 Subject: [PATCH] fix: error, update product api --- .env.public | 2 +- .gitignore | 2 +- src/lib/apis/product/delete-product.ts | 18 +----- src/lib/apis/product/get-product.ts | 10 ++-- src/lib/apis/product/update-product.ts | 17 +++--- .../ui-components/forms/avatar-input.svelte | 4 +- .../ui-components/forms/banner-input.svelte | 3 - src/lib/ui-components/views/alert.svelte | 25 +++++++++ src/routes/(sidebar)/crud/products/+page.ts | 2 +- .../(sidebar)/crud/products/Product.svelte | 40 +++++++------ .../crud/products/[id]/+page.server.ts | 56 ++++++++++++++++++- .../(sidebar)/crud/products/[id]/+page.svelte | 3 +- .../crud/products/create/+page.server.ts | 10 +++- .../crud/products/create/+page.svelte | 3 +- .../(sidebar)/crud/products/create/+page.ts | 12 ++-- 15 files changed, 139 insertions(+), 68 deletions(-) create mode 100644 src/lib/ui-components/views/alert.svelte diff --git a/.env.public b/.env.public index 40d546d..e5df712 100644 --- a/.env.public +++ b/.env.public @@ -1,2 +1,2 @@ PUBLIC_GRAPHQL_ENDPOINT="https://graphql.dev.seekhype.io/v1/graphql" -PUBLIC_API_ENDPOINT="https://ip-api.dev.aurascan.io" \ No newline at end of file +PUBLIC_API_ENDPOINT="https://ip-api.dev.aurascan.io" diff --git a/.gitignore b/.gitignore index f9f0320..41b914a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ node_modules !.env.public vite.config.js.timestamp-* vite.config.ts.timestamp-* -/test-results \ No newline at end of file +/test-results diff --git a/src/lib/apis/product/delete-product.ts b/src/lib/apis/product/delete-product.ts index 2b85cca..9bb4fe7 100644 --- a/src/lib/apis/product/delete-product.ts +++ b/src/lib/apis/product/delete-product.ts @@ -1,22 +1,6 @@ -import { env } from '$env/dynamic/public'; import { config } from '$lib/public-config'; -export interface ProductUpdateRequest { - id: number; - name: string; - category: string; - description: string; - avatar_img: string; - banner_img: string; - metadata: any; - owner_id?: number; // TODO required - featured_at: string | null; - product_attributes: { id?: number; name: string; value: string }[]; - - collections?: { id?: number; chain_id: string; contract_address: string }[]; -} - -export async function updateProduct(id: number): Promise { +export async function deleteProduct(id: number): Promise { await fetch(`${config}/products/${id}`, { method: 'DELETE', headers: { diff --git a/src/lib/apis/product/get-product.ts b/src/lib/apis/product/get-product.ts index 65a86a7..83cdafd 100644 --- a/src/lib/apis/product/get-product.ts +++ b/src/lib/apis/product/get-product.ts @@ -52,7 +52,6 @@ export async function getProductById(id: number): Promise response.json()) .then((response) => { - return { - ...response.data.ipscan_products[0], - collections: response.data.ipscan_products[0]?.collections?.map((c: any) => c.collection) - }}); + return { + ...response.data.ipscan_products[0], + collections: response.data.ipscan_products[0]?.collections?.map((c: any) => c.collection) + }; + }); } diff --git a/src/lib/apis/product/update-product.ts b/src/lib/apis/product/update-product.ts index 24af36f..265d3b4 100644 --- a/src/lib/apis/product/update-product.ts +++ b/src/lib/apis/product/update-product.ts @@ -1,21 +1,20 @@ import { config } from '$lib/public-config'; export interface ProductUpdateRequest { - id: number; name: string; - category: string; - description: string; + owner_id: number; avatar_img: string; banner_img: string; - metadata: any; - owner: { id: string }; - featured_at: string | null; - attributes: { name: string; value: string }[]; + category: string; + description: string; + metadata: { previews?: string[]; cta_link?: string }; + featured?: boolean; + attributes?: { name: string; value: string }[]; collections?: { chain_id: string; contract_address: string }[]; } -export async function updateProduct(data: ProductUpdateRequest): Promise { - await fetch(`${config.apiEndpoint}/products/${data.id}`, { +export async function updateProduct(id: number, data: ProductUpdateRequest): Promise { + return fetch(`${config.apiEndpoint}/products/${id}`, { method: 'PUT', body: JSON.stringify(data), headers: { diff --git a/src/lib/ui-components/forms/avatar-input.svelte b/src/lib/ui-components/forms/avatar-input.svelte index cf013dc..0c09385 100644 --- a/src/lib/ui-components/forms/avatar-input.svelte +++ b/src/lib/ui-components/forms/avatar-input.svelte @@ -1,5 +1,5 @@ + +{description} diff --git a/src/routes/(sidebar)/crud/products/+page.ts b/src/routes/(sidebar)/crud/products/+page.ts index 35ca5f1..a193f78 100644 --- a/src/routes/(sidebar)/crud/products/+page.ts +++ b/src/routes/(sidebar)/crud/products/+page.ts @@ -6,7 +6,7 @@ import { type ProductGetResponseData } from '$lib/apis/product/get-product'; export interface ProductPageData { mode?: string; - product?: ProductGetResponseData; + product: ProductGetResponseData; statuses: string[]; selected_statuses?: string[]; genres: string[]; diff --git a/src/routes/(sidebar)/crud/products/Product.svelte b/src/routes/(sidebar)/crud/products/Product.svelte index 0af03f4..47e9420 100644 --- a/src/routes/(sidebar)/crud/products/Product.svelte +++ b/src/routes/(sidebar)/crud/products/Product.svelte @@ -9,6 +9,8 @@ Toggle } from 'flowbite-svelte'; import { CheckOutline, EditOutline, PlusOutline, TrashBinSolid } from 'flowbite-svelte-icons'; + import { enhance } from '$app/forms'; + import Delete from './Delete.svelte'; import Input from '$lib/ui-components/forms/input.svelte'; import Textarea from '$lib/ui-components/forms/text-area.svelte'; @@ -20,12 +22,11 @@ import AvatarInput from '$lib/ui-components/forms/avatar-input.svelte'; import type { ProductPageData } from './+page'; - import Delete from './Delete.svelte'; - import _ from 'underscore'; import ClonableSelectInput from '$lib/ui-components/forms/clonable-select-input.svelte'; import ClonableInputInput from '$lib/ui-components/forms/clonable-input-input.svelte'; import { CHAINS, PAGE_MODE, PRODUCT_CATEGORIES } from '$lib/constants'; + import Alert from '$lib/ui-components/views/alert.svelte'; export let data: ProductPageData; export let mode: string = PAGE_MODE.CREATE; @@ -38,15 +39,20 @@ let openDelete: boolean = false; $: isViewMode = mode === PAGE_MODE.VIEW; - - console.log(form); -
+
-
+
+ {#if form?.error} + + {/if} Products {isViewMode ? 'View' : 'Edit'} @@ -56,7 +62,7 @@ @@ -73,7 +79,7 @@ Featured @@ -89,7 +95,7 @@ ({ src: p }))} + selectedFiles={data.product.metadata?.previews?.map((p) => ({ src: p }))} inputProps={{ name: 'previews', disabled: isViewMode }} /> { + default: async ({ params, request }) => { + const id = parseInt(params.id); const data = await request.formData(); - console.log(data); + + const requestData = { + // banner_img: data.get('banner_img') as string, // TODO upload banner + // avatar_img: data.get('avatar_img') as string, // TODO upload img + banner_img: 'https://picsum.photos/seed/4mv5QDNfnf/640/480', + avatar_img: 'https://picsum.photos/seed/4mv5QDNfnf/640/480', + name: data.get('name') as string, + featured: data.get('featured') === 'true', + category: data.get('category') as string, + collections: JSON.parse(data.get('collections') as string), + description: data.get('about') as string, + owner_id: parseInt(data.get('creator') as string), // TODO get users + metadata: { + // previews: data.get("previews"), TODO upload then use url + previews: JSON.parse(data.get('previews') as string).map(() => 'http://demmo.jjj'), + cta_url: data.get('cta_url') || undefined + }, + attributes: [ + ...JSON.parse(data.get('statuses') as string).map((value: string) => ({ + name: 'status', + value + })), + ...JSON.parse(data.get('genres') as string).map((value: string) => ({ + name: 'genre', + value + })), + ...JSON.parse(data.get('players_infos') as string).map((value: string) => ({ + name: 'players info', + value + })), + ...JSON.parse(data.get('game_modes') as string).map((value: string) => ({ + name: 'game mode', + value + })) + ] + }; + + const updateResponse = await updateProduct(id, requestData); + + const responseData = await updateResponse.json(); + + console.log('responseData', responseData); // TODO remove + + if (updateResponse.status === 200) { + throw redirect(303, `/crud/products/${id}`); // TODO force reload from server + } else { + return fail(responseData.statusCode, responseData); + } } }; diff --git a/src/routes/(sidebar)/crud/products/[id]/+page.svelte b/src/routes/(sidebar)/crud/products/[id]/+page.svelte index 9fddbdf..a00fe97 100644 --- a/src/routes/(sidebar)/crud/products/[id]/+page.svelte +++ b/src/routes/(sidebar)/crud/products/[id]/+page.svelte @@ -6,6 +6,7 @@ export let data: ProductPageData; export let mode: string = data.mode || PAGE_MODE.VIEW; + export let form: any = undefined; const path: string = '/crud/products'; $: description = `A place to ${mode} a single product`; @@ -15,4 +16,4 @@ - + diff --git a/src/routes/(sidebar)/crud/products/create/+page.server.ts b/src/routes/(sidebar)/crud/products/create/+page.server.ts index 4d1a0a8..5aa1e79 100644 --- a/src/routes/(sidebar)/crud/products/create/+page.server.ts +++ b/src/routes/(sidebar)/crud/products/create/+page.server.ts @@ -6,14 +6,16 @@ export const actions = { const data = await request.formData(); const requestData = { - banner_img: data.get('banner_img') as string, // TODO upload banner - avatar_img: data.get('avatar_img') as string, // TODO upload img + // banner_img: data.get('banner_img') as string, // TODO upload banner + // avatar_img: data.get('avatar_img') as string, // TODO upload img + banner_img: 'https://picsum.photos/seed/4mv5QDNfnf/640/480', + avatar_img: 'https://picsum.photos/seed/4mv5QDNfnf/640/480', name: data.get('name') as string, featured: data.get('featured') === 'true', category: data.get('category') as string, collections: JSON.parse(data.get('collections') as string), description: data.get('about') as string, - owner_id: 1, // TODO get users + owner_id: parseInt(data.get('creator') as string), // TODO get users metadata: { // previews: data.get("previews"), TODO upload then use url previews: JSON.parse(data.get('previews') as string).map(() => 'http://demmo.jjj'), @@ -43,6 +45,8 @@ export const actions = { const responseData = await createResponse.json(); + console.log('responseData', responseData); // TODO remove + if (createResponse.status === 200) { throw redirect(303, `/crud/products/${responseData.data.id}`); } else { diff --git a/src/routes/(sidebar)/crud/products/create/+page.svelte b/src/routes/(sidebar)/crud/products/create/+page.svelte index dee32a9..32fea47 100644 --- a/src/routes/(sidebar)/crud/products/create/+page.svelte +++ b/src/routes/(sidebar)/crud/products/create/+page.svelte @@ -6,6 +6,7 @@ export let data: ProductPageData; export let mode: string = PAGE_MODE.CREATE; + export let form: any = undefined; const path: string = '/crud/products'; $: description = `A place to create a single product`; @@ -15,4 +16,4 @@ - + diff --git a/src/routes/(sidebar)/crud/products/create/+page.ts b/src/routes/(sidebar)/crud/products/create/+page.ts index 76310a6..331d605 100644 --- a/src/routes/(sidebar)/crud/products/create/+page.ts +++ b/src/routes/(sidebar)/crud/products/create/+page.ts @@ -10,15 +10,17 @@ export async function load(): Promise { return { product: { name: '', - category: '', - description: '', + owner: { + id: undefined, + name: undefined + }, avatar_img: '', banner_img: '', - owner: {}, - metadata: {}, + category: '', + description: '', featured_at: null, attributes: [], - collections: [] + metadata: undefined }, statuses: nameToValues['status']?.map((v) => v.value), genres: nameToValues['genre']?.map((v) => v.value),