Skip to content

Commit

Permalink
fix: error, update product api
Browse files Browse the repository at this point in the history
  • Loading branch information
HungLV46 committed Aug 16, 2024
1 parent a374c8c commit 74c3933
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .env.public
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
PUBLIC_GRAPHQL_ENDPOINT="https://graphql.dev.seekhype.io/v1/graphql"
PUBLIC_API_ENDPOINT="https://ip-api.dev.aurascan.io"
PUBLIC_API_ENDPOINT="https://ip-api.dev.aurascan.io"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ node_modules
!.env.public
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
/test-results
/test-results
18 changes: 1 addition & 17 deletions src/lib/apis/product/delete-product.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
export async function deleteProduct(id: number): Promise<void> {
await fetch(`${config}/products/${id}`, {
method: 'DELETE',
headers: {
Expand Down
10 changes: 5 additions & 5 deletions src/lib/apis/product/get-product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export async function getProductById(id: number): Promise<ProductGetResponseData
}
collections: product_collections {
collection {
id
chain_id
contract_address
}
Expand All @@ -71,8 +70,9 @@ export async function getProductById(id: number): Promise<ProductGetResponseData
})
.then((response) => 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)
};
});
}
17 changes: 8 additions & 9 deletions src/lib/apis/product/update-product.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
await fetch(`${config.apiEndpoint}/products/${data.id}`, {
export async function updateProduct(id: number, data: ProductUpdateRequest): Promise<Response> {
return fetch(`${config.apiEndpoint}/products/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
headers: {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ui-components/forms/avatar-input.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { Button, Dropzone } from 'flowbite-svelte';
import { Dropzone } from 'flowbite-svelte';
import { MinusOutline } from 'flowbite-svelte-icons';
type Src = string | null | undefined;
Expand All @@ -8,7 +8,7 @@
function handleFileChange(event: Event) {
const files = (event.target as HTMLInputElement)?.files || [];
console.log(files);
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file && file.type.startsWith('image/')) {
Expand Down
3 changes: 0 additions & 3 deletions src/lib/ui-components/forms/banner-input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,4 @@
border-top-right-radius: 0.5rem;
object-fit: cover;
}
img[style*='height'] {
max-height: unset;
}
</style>
25 changes: 25 additions & 0 deletions src/lib/ui-components/views/alert.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import { Alert } from 'flowbite-svelte';
import { twMerge } from 'tailwind-merge';
const typesToColor = {
info: 'blue',
warning: 'yellow',
success: 'green',
error: 'red'
};
type Type = keyof typeof typesToColor;
type Color = 'blue' | 'yellow' | 'green' | 'red' | undefined;
export let type: Type = 'info';
export let description: string = 'Alert description';
const color = typesToColor[type] as Color;
</script>

<Alert
class={twMerge('fixed left-[60%] z-20 translate-x-[-50%]', $$props.class)}
{color}
dismissable
{...$$restProps}>{description}</Alert
>
2 changes: 1 addition & 1 deletion src/routes/(sidebar)/crud/products/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
40 changes: 23 additions & 17 deletions src/routes/(sidebar)/crud/products/Product.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -38,15 +39,20 @@
let openDelete: boolean = false;
$: isViewMode = mode === PAGE_MODE.VIEW;
console.log(form);
</script>

<MetaTag {path} {description} {title} {subtitle} />

<form method="POST">
<form method="POST" enctype="multipart/form-data" use:enhance>
<main class="relative h-full w-full overflow-y-auto bg-white dark:bg-gray-800">
<div class="p-4">
<div class="mt-10 p-4">
{#if form?.error}
<Alert
class="fixed left-[60%] z-20 translate-x-[-50%]"
type="error"
description={form.message}
/>
{/if}
<Breadcrumb class="mb-5">
<BreadcrumbItem home href="/crud/products">Products</BreadcrumbItem>
<BreadcrumbItem>{isViewMode ? 'View' : 'Edit'}</BreadcrumbItem>
Expand All @@ -56,7 +62,7 @@
</Heading>
<BannerInput
name="banner_img"
src={data.product?.banner_img}
src={data.product.banner_img}
alt="please select a product banner!"
class="max-w-screen-xl"
disabled={isViewMode}
Expand All @@ -65,31 +71,31 @@
<div class="mb-7 flex flex-row">
<AvatarInput
name="avatar_img"
src={data.product?.avatar_img}
src={data.product.avatar_img}
alt="please select a product avatar!"
disabled={isViewMode}
/>
<div class="ml-4 flex flex-col space-y-3">
<Input
class="w-22 me-4"
placeholder="Product name"
value={data.product?.name}
value={data.product.name}
inputProps={{ name: 'name', disabled: isViewMode }}
/>
<Toggle
name="featured"
class="me-4"
size="small"
color="blue"
checked={!_.isEmpty(data.product?.featured_at)}
checked={!_.isEmpty(data.product.featured_at)}
disabled={isViewMode}
>
Featured
</Toggle>
<Select
class="w-22 me-4"
items={PRODUCT_CATEGORIES.map((c) => ({ name: c, value: c }))}
selected={data.product?.category || ''}
selected={data.product.category || ''}
selectProps={{
name: 'category',
disabled: isViewMode
Expand Down Expand Up @@ -137,7 +143,7 @@
<Label>Link Collection(s)</Label>
<ClonableSelectInput
name="collections"
items={data.product?.collections || []}
items={data.product.collections || []}
selectProps={{
name: 'Chain',
class: 'mb-2 me-4 mt-3 w-48',
Expand All @@ -164,31 +170,31 @@
name="About"
placeholder="Product description"
class="w-22 mb-2 me-4 mt-3 w-full"
value={data.product?.description}
value={data.product.description}
textareaProps={{ name: 'about', disabled: isViewMode }}
/>
<Input
name="Creator"
placeholder="e.g. Robert Perez"
class="w-22 mb-2 me-4 mt-3"
value={data.product?.owner?.name}
value={data.product.owner?.name}
inputProps={{ name: 'creator', disabled: isViewMode }}
/>
<ImageInput
name="Overview pictures/media"
selectedFiles={data.product?.metadata?.previews?.map((p) => ({ src: p }))}
selectedFiles={data.product.metadata?.previews?.map((p) => ({ src: p }))}
inputProps={{ name: 'previews', disabled: isViewMode }}
/>
<Input
name="CTA link"
placeholder="Call to action link"
class="w-22 mb-2 me-4 mt-3"
value={data.product?.metadata?.cta_url}
value={data.product.metadata?.cta_url}
inputProps={{ name: 'cta_url', disabled: isViewMode }}
/>
<ClonableInputInput
name="socials"
items={data.product?.metadata?.socials}
items={data.product.metadata?.socials}
inputPropsList={[
{
name: 'Social',
Expand Down
56 changes: 54 additions & 2 deletions src/routes/(sidebar)/crud/products/[id]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,58 @@
import { updateProduct } from '$lib/apis/product/update-product.js';
import { fail, redirect } from '@sveltejs/kit';
import { invalidateAll } from '$app/navigation';

export const actions = {
default: async ({ cookies, request }) => {
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);
}
}
};
3 changes: 2 additions & 1 deletion src/routes/(sidebar)/crud/products/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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`;
Expand All @@ -15,4 +16,4 @@

<MetaTag {path} {description} {title} {subtitle} />

<ProductPage {data} {mode} />
<ProductPage {data} {mode} {form} />
10 changes: 7 additions & 3 deletions src/routes/(sidebar)/crud/products/create/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 74c3933

Please sign in to comment.