Skip to content

Commit

Permalink
feat: creator
Browse files Browse the repository at this point in the history
  • Loading branch information
HungLV46 committed Aug 18, 2024
1 parent 4262cb2 commit 6d7f753
Show file tree
Hide file tree
Showing 25 changed files with 808 additions and 244 deletions.
14 changes: 7 additions & 7 deletions src/lib/apis/product/create-product.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { config } from '$lib/public-config';

export interface CreateProductRequest {
name: string;
owner_id: number;
avatar_img: string;
banner_img: string;
category: string;
description: string;
metadata: { previews?: string[]; cta_link?: string };
name?: string;
owner_id?: number;
avatar_img?: string;
banner_img?: 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 }[];
Expand Down
14 changes: 7 additions & 7 deletions src/lib/apis/product/update-product.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { config } from '$lib/public-config';

export interface ProductUpdateRequest {
name: string;
owner_id: number;
avatar_img: string;
banner_img: string;
category: string;
description: string;
metadata: { previews?: string[]; cta_link?: string };
name?: string;
owner_id?: number;
avatar_img?: string;
banner_img?: string;
category?: string;
description?: string;
metadata?: { previews?: string[]; cta_link?: string; socials?: { name: string; url: string }[] };
featured?: boolean;
attributes?: { name: string; value: string }[];
collections?: { chain_id: string; contract_address: string }[];
Expand Down
24 changes: 24 additions & 0 deletions src/lib/apis/user/create-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { config } from '$lib/public-config';

export interface CreateProductRequest {
name: string;
owner_id: number;
avatar_img: string;
banner_img: 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 createProduct(data: CreateProductRequest): Promise<Response> {
return fetch(`${config.apiEndpoint}/products`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
});
}
10 changes: 10 additions & 0 deletions src/lib/apis/user/delete-product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { config } from '$lib/public-config';

export async function deleteProduct(id: number): Promise<void> {
await fetch(`${config}/products/${id}`, {
method: 'DELETE',
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
});
}
50 changes: 50 additions & 0 deletions src/lib/apis/user/get-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { config } from '$lib/public-config';

export interface UserGetResponseData {
id: number;
name?: string;
email?: string;
bio?: string;
banner_img?: string;
avatar_img?: string;
additional_info?: {
headline?: string;
location?: string;
socials?: { name: string; url: string }[];
wallets: { address: string }[];
};
attributes: { name: string; value: string }[];
}

export async function getUserById(id: number): Promise<UserGetResponseData> {
const operationName = 'getUserById';

const operationsDoc = `
query getUserById($id: Int = 0) {
ipscan_ipscan_user(where: {id: {_eq: $id}}) {
id
name
email
bio
banner_img
avatar_img
additional_info
}
}
`;

return fetch(config.graphqlEndpoint, {
method: 'POST',
body: JSON.stringify({
query: operationsDoc,
variables: { id: id },
operationName: operationName
})
})
.then((response) => response.json())
.then((response) => {
return {
...response.data.ipscan_ipscan_user[0]
};
});
}
31 changes: 31 additions & 0 deletions src/lib/apis/user/list-user-attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { config } from '$lib/public-config';
import type { ListResponse } from '../types';

export interface UserAttribute {
name: string;
value: string;
}

export async function listUserAttributes(): Promise<ListResponse<UserAttribute>> {
const operationName = 'listUserAttributes';

const operationsDoc = `
query ${operationName} {
ipscan_user_attributes(distinct_on: [name, value]) {
name
value
}
}
`;

return fetch(config.graphqlEndpoint, {
method: 'POST',
body: JSON.stringify({
query: operationsDoc,
variables: {},
operationName: operationName
})
})
.then((response) => response.json())
.then((response) => ({ items: response.data.ipscan_user_attributes }));
}
107 changes: 107 additions & 0 deletions src/lib/apis/user/list-users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { config } from '$lib/public-config';
import type { ListWithPagingResponse } from '../types';

export interface ListUserQuery {
name?: string;
order_by?: { [key: string]: 'asc' | 'desc' };
limit: number;
offset: number;
}

export interface UserResponse {
id: number;
name: string;
avatar_img: string;
no_products: number;
no_collections: number;
no_nfts: number;
}

export async function listUser(
variables: undefined | ListUserQuery = { offset: 0, limit: 10 }
): Promise<ListWithPagingResponse<UserResponse>> {
const operationName = 'ipscanListCreators';

console.log(variables);

// TODO check query performance
const operationsDoc = `
query ${operationName}($name: String, $limit: Int = 10, $offset: Int = 0) {
ipscan_ipscan_user(where: {name: {_ilike: $name}}, limit: $limit, offset: $offset) {
id
avatar_img
name
products_aggregate {
aggregate {
count
}
}
products {
product_collections_aggregate {
aggregate {
count
}
}
product_collections {
collection {
nfts_aggregate {
aggregate {
count
}
}
}
}
}
}
ipscan_ipscan_user_aggregate(where: {name: {_ilike: $name}}) {
aggregate {
count
}
}
}
`;

return fetch(config.graphqlEndpoint, {
method: 'POST',
body: JSON.stringify({
query: operationsDoc,
variables: variables,
operationName: operationName
})
})
.then((response) => response.json())
.then((response) => {
console.log('response', response);
const items = [];
// sum all number of collections & nfts
for (const user of response.data.ipscan_ipscan_user) {
const item = {
id: user.id,
avatar_img: user.avatar_img,
name: user.name,
no_products: user.products_aggregate.aggregate.count,
no_collections: 0,
no_nfts: 0
};

for (const product of user.products) {
item.no_collections += product.product_collections_aggregate.aggregate.count;

for (const collection of product.product_collections) {
item.no_nfts += collection.collection.nfts_aggregate.aggregate.count;
}
}

items.push(item);
}

return {
items: items,
paging: {
total: parseInt(response.data.ipscan_ipscan_user_aggregate.aggregate.count),
limit: variables.limit,
offset: variables.offset
}
};
});
}
26 changes: 26 additions & 0 deletions src/lib/apis/user/update-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { config } from '$lib/public-config';

export interface UserUpdateRequest {
name?: string;
email?: string;
bio?: string;
banner_img?: string;
avatar_img?: string;
additional_info?: {
headline?: string;
location?: string;
socials?: { name: string; url: string }[];
wallets: { address: string }[];
};
attributes?: { name: string; value: string }[];
}

export async function updateUser(id: number, data: UserUpdateRequest): Promise<Response> {
return fetch(`${config.apiEndpoint}/users/${id}`, {
method: 'PUT',
body: JSON.stringify(data),
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
});
}
15 changes: 15 additions & 0 deletions src/lib/apis/utils/upload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// import { config } from "$lib/public-config";

export async function upload(file: File) {
const formData = new FormData();
formData.append('file', file);

// TODO use config
// const response = await fetch(`${config.apiEndpoint}/upload`, {
const response = await fetch(`http://localhost:3000/upload`, {
method: 'POST',
body: formData
});

return (await response.json()) as { data: { s3_url: string } };
}
17 changes: 4 additions & 13 deletions src/lib/ui-components/forms/avatar-input.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { Dropzone } from 'flowbite-svelte';
import { MinusOutline } from 'flowbite-svelte-icons';
import { PlusOutline } from 'flowbite-svelte-icons';
type Src = string | null | undefined;
export let src: Src = undefined;
Expand All @@ -23,31 +23,22 @@
</script>

<div class="relative">
<Dropzone
{...$$restProps}
class="relative h-32 w-32"
on:change={handleFileChange}
on:click={(event) => console.log(event)}
>
<Dropzone {...$$restProps} class="relative h-32 w-32" on:change={handleFileChange}>
{#if src}
<img {src} alt="avatar" />
{:else}
<span class="absolute inset-0 flex items-center justify-center text-gray-500">
{alt}
</span>
{/if}
<!-- little close button to remove the -->
<!-- a botton showing that we are editing, doesn't do anything more (at least for now) -->
{#if !$$props.disabled}
<button
class="absolute right-3 top-3 h-5 w-5 rounded-full bg-red-300 p-1 text-red-500 hover:bg-red-500 hover:text-white"
style="line-height: 1.25rem; padding: 0;"
type="button"
on:click={(event) => {
src = undefined;
event.stopPropagation();
}}
>
<MinusOutline />
<PlusOutline />
</button>
{/if}
</Dropzone>
Expand Down
9 changes: 3 additions & 6 deletions src/lib/ui-components/forms/banner-input.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { Dropzone } from 'flowbite-svelte';
import { MinusOutline } from 'flowbite-svelte-icons';
import { MinusOutline, PlusOutline } from 'flowbite-svelte-icons';
import { twMerge } from 'tailwind-merge';
type Src = string | null | undefined;
Expand Down Expand Up @@ -31,17 +31,14 @@
{alt}
</span>
{/if}
<!-- a botton showing that we are editing, doesn't do anything more (at least for now) -->
{#if !$$props.disabled}
<button
class="absolute right-3 top-3 h-5 w-5 rounded-full bg-red-300 p-1 text-red-500 hover:bg-red-500 hover:text-white"
style="line-height: 1.25rem; padding: 0;"
type="button"
on:click={(event) => {
src = undefined;
event.stopPropagation();
}}
>
<MinusOutline />
<PlusOutline />
</button>
{/if}
</Dropzone>
Expand Down
4 changes: 2 additions & 2 deletions src/lib/ui-components/forms/image-input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
{#if name}
<Label class="mb-1 ml-3" {...labelProps}>{name}</Label>
{/if}
<input type="hidden" name={inputProps?.name} value={JSON.stringify(selectedFiles)} />
<Input type="file" on:change={handleFileChange} multiple {..._.omit(inputProps, 'name')} />
<input type="hidden" name={`prev_${name}`} value={JSON.stringify(selectedFiles)} />
<Input type="file" on:change={handleFileChange} multiple {...inputProps} />
<Gallery bind:items={selectedFiles} class="grid-cols-2 gap-4 md:grid-cols-3" />
</div>
Loading

0 comments on commit 6d7f753

Please sign in to comment.