From 16e002546e12c5cfc34c0aff1d2ee826d724a198 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Sat, 8 Jun 2024 12:38:01 +0500
Subject: [PATCH 01/14] add(profiles): allow clearing profile banner and image
---
components/profile/create/Modal.vue | 2 +-
components/profile/create/SelectImageField.vue | 10 ++++++++--
components/profile/create/stages/Form.vue | 8 ++++++--
services/profile.ts | 4 ++--
4 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 0d94614989..acc135af59 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -109,7 +109,7 @@ const processProfile = async (profileData: ProfileFormData) => {
name: profileData.name,
description: profileData.description,
image: imageUrl,
- banner: bannerUrl,
+ banner: hasProfile.value ? bannerUrl ?? null : bannerUrl!,
socials: constructSocials(profileData),
}
diff --git a/components/profile/create/SelectImageField.vue b/components/profile/create/SelectImageField.vue
index 6bc107aaa4..0c84b3c2a5 100644
--- a/components/profile/create/SelectImageField.vue
+++ b/components/profile/create/SelectImageField.vue
@@ -21,12 +21,12 @@
vSelectedFile?.name ?? 'Click To Select A File'
}}
+ @click="clear" />
@@ -35,6 +35,7 @@ import { NeoButton, NeoIcon, NeoUpload } from '@kodadot1/brick'
const NuxtImg = resolveComponent('NuxtImg')
+const emits = defineEmits(['clear'])
const props = defineProps<{
modelValue: File | null
preview?: string
@@ -46,6 +47,11 @@ const selectedFilePreview = computed(() =>
vSelectedFile.value ? URL.createObjectURL(vSelectedFile.value as File) : '',
)
+const clear = () => {
+ vSelectedFile.value = null
+ emits('clear')
+}
+
const fileSelected = (file: File | null) => {
vSelectedFile.value = file
}
diff --git a/components/profile/create/stages/Form.vue b/components/profile/create/stages/Form.vue
index 7f9008464a..61cced8ee8 100644
--- a/components/profile/create/stages/Form.vue
+++ b/components/profile/create/stages/Form.vue
@@ -45,7 +45,10 @@
Recommended: 400x400px, up to 2MB (JPG, PNG)
-
+
@@ -60,7 +63,8 @@
+ :preview="form.bannerPreview"
+ @clear="form.bannerPreview = undefined" />
diff --git a/services/profile.ts b/services/profile.ts
index b8bbf69037..d489741b4f 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -44,7 +44,7 @@ export type CreateProfileRequest = {
name: string
description: string
image: string
- banner: string
+ banner: string | undefined
socials: SocialLink[]
}
@@ -53,7 +53,7 @@ export type UpdateProfileRequest = {
name?: string
description?: string
image?: string
- banner?: string
+ banner: string | null
socials: SocialLink[]
}
From 186818a881019bae342133104a1666643da7d709 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Sat, 8 Jun 2024 13:19:02 +0500
Subject: [PATCH 02/14] ref(SelectImageField.vue): rename emits to emit
---
components/profile/create/SelectImageField.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/components/profile/create/SelectImageField.vue b/components/profile/create/SelectImageField.vue
index 0c84b3c2a5..eab5bac8ff 100644
--- a/components/profile/create/SelectImageField.vue
+++ b/components/profile/create/SelectImageField.vue
@@ -35,7 +35,7 @@ import { NeoButton, NeoIcon, NeoUpload } from '@kodadot1/brick'
const NuxtImg = resolveComponent('NuxtImg')
-const emits = defineEmits(['clear'])
+const emit = defineEmits(['clear'])
const props = defineProps<{
modelValue: File | null
preview?: string
@@ -49,7 +49,7 @@ const selectedFilePreview = computed(() =>
const clear = () => {
vSelectedFile.value = null
- emits('clear')
+ emit('clear')
}
const fileSelected = (file: File | null) => {
From 1628853a494f0de6c5bc1ab324fdae1e52bbd875 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Sat, 8 Jun 2024 14:11:41 +0500
Subject: [PATCH 03/14] add(profiles): delete profile feature
---
components/profile/ProfileDetail.vue | 5 +-
components/profile/create/Modal.vue | 17 ++-
components/profile/create/stages/Form.vue | 140 +++++++++++++---------
locales/en.json | 4 +-
services/profile.ts | 13 ++
5 files changed, 118 insertions(+), 61 deletions(-)
diff --git a/components/profile/ProfileDetail.vue b/components/profile/ProfileDetail.vue
index e07591ef99..a4b2fe24ac 100644
--- a/components/profile/ProfileDetail.vue
+++ b/components/profile/ProfileDetail.vue
@@ -1,6 +1,9 @@
-
+
+ @submit="handleFormSubmition"
+ @delete="handleProfileDelete" />
@@ -36,6 +37,7 @@ import {
SocialLink,
UpdateProfileRequest,
createProfile,
+ deleteProfile,
updateProfile,
} from '@/services/profile'
import { rateLimitedPinFileToIPFS } from '@/services/nftStorage'
@@ -56,7 +58,7 @@ const hasProfile = computed(() => profile?.hasProfile.value)
const initialStep = computed(() => (hasProfile.value ? 2 : 1))
-const emit = defineEmits(['close', 'success'])
+const emit = defineEmits(['close', 'success', 'deleted'])
const vOpen = useVModel(props, 'modelValue')
const stage = ref(initialStep.value)
@@ -118,6 +120,17 @@ const processProfile = async (profileData: ProfileFormData) => {
: createProfile(profileBody as CreateProfileRequest)
}
+const handleProfileDelete = async (address: string) => {
+ try {
+ await deleteProfile(address)
+ emit('deleted')
+ close()
+ } catch (error) {
+ warningMessage(error!.toString())
+ console.error(error)
+ }
+}
+
const handleFormSubmition = async (profileData: ProfileFormData) => {
stage.value = 4 // Go to loading stage
try {
diff --git a/components/profile/create/stages/Form.vue b/components/profile/create/stages/Form.vue
index 61cced8ee8..5e97ff3fad 100644
--- a/components/profile/create/stages/Form.vue
+++ b/components/profile/create/stages/Form.vue
@@ -91,14 +91,34 @@
-
+
+
+
+
+
+ {{
+ !deleteConfirm
+ ? $t('profiles.delete')
+ : $t('profiles.deleteConfirm')
+ }}
+
+
+
+
+
@@ -111,33 +131,69 @@ import { Profile } from '@/services/profile'
import { addHttpToUrl } from '@/utils/url'
import { StatusAPIResponse } from '@farcaster/auth-client'
-const { accountId } = useAuth()
+const FarcasterIcon = defineAsyncComponent(
+ () => import('@/assets/icons/farcaster-icon.svg?component'),
+)
+const socialLinks = [
+ {
+ name: 'farcaster',
+ icon: FarcasterIcon,
+ model: 'farcasterHandle',
+ placeholder: 'Farcaster Handle',
+ testId: 'create-profile-input-farcaster-handle',
+ },
+ {
+ name: 'website',
+ icon: () => h(NeoIcon, { icon: 'globe', pack: 'fas' }),
+ model: 'website',
+ placeholder: 'Website',
+ testId: 'create-profile-input-website',
+ },
+ {
+ name: 'twitter',
+ icon: () => h(NeoIcon, { icon: 'twitter', pack: 'fab' }),
+ model: 'twitterHandle',
+ placeholder: 'Twitter Handle',
+ testId: 'create-profile-input-twitter-handle',
+ },
+]
+
+const emit = defineEmits<{
+ (e: 'submit', value: ProfileFormData): void
+ (e: 'delete', address: string): void
+}>()
const props = defineProps<{
farcasterUserData?: StatusAPIResponse
useFarcaster: boolean
}>()
+const deleteConfirm = ref(false)
+
+const { accountId } = useAuth()
const profile = inject<{ userProfile: Ref; hasProfile: Ref }>(
'userProfile',
)
-const userProfile = computed(() => profile?.userProfile.value)
-const substrateAddress = computed(() => formatAddress(accountId.value, 42))
-
-const FarcasterIcon = defineAsyncComponent(
- () => import('@/assets/icons/farcaster-icon.svg?component'),
-)
+const substrateAddress = computed(() => formatAddress(accountId.value, 42))
+const form = reactive({
+ address: substrateAddress.value,
+ name: '',
+ description: '',
+ image: null,
+ imagePreview: undefined,
+ banner: null,
+ bannerPreview: undefined,
+ farcasterHandle: undefined,
+ twitterHandle: undefined,
+ website: undefined,
+})
+const userProfile = computed(() => profile?.userProfile.value)
const missingImage = computed(() => (form.imagePreview ? false : !form.image))
-
const submitDisabled = computed(
() => !form.name || !form.description || missingImage.value,
)
-const emit = defineEmits<{
- (e: 'submit', value: ProfileFormData): void
-}>()
-
const validatingFormInput = (model: string) => {
switch (model) {
case 'farcasterHandle':
@@ -153,43 +209,13 @@ const validatingFormInput = (model: string) => {
}
}
-// form state
-const form = reactive({
- address: substrateAddress.value,
- name: '',
- description: '',
- image: null,
- imagePreview: undefined,
- banner: null,
- bannerPreview: undefined,
- farcasterHandle: undefined,
- twitterHandle: undefined,
- website: undefined,
-})
-
-const socialLinks = [
- {
- name: 'farcaster',
- icon: FarcasterIcon,
- model: 'farcasterHandle',
- placeholder: 'Farcaster Handle',
- testId: 'create-profile-input-farcaster-handle',
- },
- {
- name: 'website',
- icon: () => h(NeoIcon, { icon: 'globe', pack: 'fas' }),
- model: 'website',
- placeholder: 'Website',
- testId: 'create-profile-input-website',
- },
- {
- name: 'twitter',
- icon: () => h(NeoIcon, { icon: 'twitter', pack: 'fab' }),
- model: 'twitterHandle',
- placeholder: 'Twitter Handle',
- testId: 'create-profile-input-twitter-handle',
- },
-]
+const deleteProfile = () => {
+ if (deleteConfirm.value) {
+ emit('delete', substrateAddress.value)
+ } else {
+ deleteConfirm.value = true
+ }
+}
watchEffect(async () => {
const profile = userProfile.value
diff --git a/locales/en.json b/locales/en.json
index a9fd893690..04ad06ab0e 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -2104,6 +2104,8 @@
"title": "Unsuccessful Connection",
"message": "Somehting went wrong linking with your farcaster account, please try again."
}
- }
+ },
+ "delete": "Reset all Fields - start over",
+ "deleteConfirm": "You sure? - click again"
}
}
diff --git a/services/profile.ts b/services/profile.ts
index d489741b4f..eec722d630 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -142,6 +142,19 @@ export const updateProfile = async (updates: UpdateProfileRequest) => {
}
}
+export const deleteProfile = async (address: string) => {
+ try {
+ const response = await api(`/profiles/${address}`, {
+ method: 'DELETE',
+ })
+ return response
+ } catch (error) {
+ throw new Error(
+ `[PROFILE::DELETE] ERROR: ${(error as FetchError)?.data?.error?.issues[0]?.message}`,
+ )
+ }
+}
+
export const follow = async (followRequest: FollowRequest) => {
try {
const response = await api('/follow', {
From 414daf5d07be7773c28fc89a3977e4f85910f908 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Sat, 8 Jun 2024 16:51:35 +0500
Subject: [PATCH 04/14] add(profiles): upload profile image
---
components/profile/create/Modal.vue | 34 +++++++++++++++++++------
services/profile.ts | 39 +++++++++++++++++++++++++++--
2 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 8c0e639f98..7febca4d02 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -34,13 +34,15 @@ import {
} from './stages/index'
import {
CreateProfileRequest,
+ ProfileImageType,
SocialLink,
UpdateProfileRequest,
createProfile,
deleteProfile,
+ getObjectUrl,
updateProfile,
+ uploadProfileImage,
} from '@/services/profile'
-import { rateLimitedPinFileToIPFS } from '@/services/nftStorage'
import { appClient, createChannel } from '@/services/farcaster'
import { StatusAPIResponse } from '@farcaster/auth-client'
import { useDocumentVisibility } from '@vueuse/core'
@@ -70,11 +72,19 @@ const close = () => {
emit('close')
}
-const uploadImage = async (
- imageFile: File | null,
-): Promise =>
- imageFile
- ? sanitizeIpfsUrl(await rateLimitedPinFileToIPFS(imageFile))
+const uploadImage = async ({
+ file,
+ type,
+ address,
+}: {
+ file: File | null
+ type: ProfileImageType
+ address: string
+}): Promise =>
+ file
+ ? await uploadProfileImage({ file, address, type }).then((response) =>
+ getObjectUrl(response.data?.key as string),
+ )
: undefined
const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
@@ -99,11 +109,19 @@ const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
const processProfile = async (profileData: ProfileFormData) => {
const imageUrl = profileData.image
- ? await uploadImage(profileData.image)
+ ? await uploadImage({
+ file: profileData.image,
+ address: profileData.address,
+ type: 'image',
+ })
: profileData.imagePreview
const bannerUrl = profileData.banner
- ? await uploadImage(profileData.banner)
+ ? await uploadImage({
+ file: profileData.banner,
+ address: profileData.address,
+ type: 'banner',
+ })
: profileData.bannerPreview
const profileBody: CreateProfileRequest | UpdateProfileRequest = {
diff --git a/services/profile.ts b/services/profile.ts
index eec722d630..f7c992d846 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -9,6 +9,12 @@ const api = $fetch.create({
baseURL: BASE_URL,
})
+const PUBLIC_R2_BUCKET_URL = isProduction
+ ? 'https://playground-r2.koda.art'
+ : 'https://pub-adc77a8fecb9405b9573442870905a67.r2.dev'
+
+export const getObjectUrl = (key: string) => `${PUBLIC_R2_BUCKET_URL}/${key}`
+
// Types for API request and response objects
export type Profile = {
address: string
@@ -32,10 +38,10 @@ export type SocialLink = {
link: string
}
-export type ProfileResponse = {
+export type ProfileResponse = {
success: boolean
message: string
- data?: Profile
+ data?: T
profileId?: string
}
@@ -57,6 +63,14 @@ export type UpdateProfileRequest = {
socials: SocialLink[]
}
+export type ProfileImageType = 'image' | 'banner'
+
+export type UploadProfileImageRequest = {
+ address: string
+ file: File
+ type: ProfileImageType
+}
+
export type FollowRequest = {
initiatorAddress: string
targetAddress: string
@@ -155,6 +169,27 @@ export const deleteProfile = async (address: string) => {
}
}
+export const uploadProfileImage = async (
+ uploadProfileImage: UploadProfileImageRequest,
+) => {
+ const form = new FormData()
+ form.append('file', uploadProfileImage.file)
+ form.append('type', uploadProfileImage.type)
+
+ try {
+ const response = await api>(
+ `/profiles/${uploadProfileImage.address}/image`,
+ {
+ method: 'POST',
+ body: form,
+ },
+ )
+ return response
+ } catch (error) {
+ throw new Error(`[PROFILE::FOLLOW] ERROR: ${(error as FetchError).data}`)
+ }
+}
+
export const follow = async (followRequest: FollowRequest) => {
try {
const response = await api('/follow', {
From e068568c852f3933caae61d13adad4ba4984200d Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 10 Jun 2024 10:43:41 +0500
Subject: [PATCH 05/14] fix(profiles): upload profile image response type
---
components/profile/create/Modal.vue | 2 +-
services/profile.ts | 15 +++++++++++----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 7febca4d02..89ff357549 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -83,7 +83,7 @@ const uploadImage = async ({
}): Promise =>
file
? await uploadProfileImage({ file, address, type }).then((response) =>
- getObjectUrl(response.data?.key as string),
+ getObjectUrl(response.key),
)
: undefined
diff --git a/services/profile.ts b/services/profile.ts
index f7c992d846..2dac91ce9b 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -38,13 +38,16 @@ export type SocialLink = {
link: string
}
-export type ProfileResponse = {
+type ProfileBaseResponse = {
success: boolean
message: string
- data?: T
- profileId?: string
}
+export type ProfileResponse = {
+ data?: Profile
+ profileId?: string
+} & ProfileBaseResponse
+
export type CreateProfileRequest = {
address: string
name: string
@@ -71,6 +74,10 @@ export type UploadProfileImageRequest = {
type: ProfileImageType
}
+export type UploadProfileImageResponse = {
+ key: string
+} & ProfileBaseResponse
+
export type FollowRequest = {
initiatorAddress: string
targetAddress: string
@@ -177,7 +184,7 @@ export const uploadProfileImage = async (
form.append('type', uploadProfileImage.type)
try {
- const response = await api>(
+ const response = await api(
`/profiles/${uploadProfileImage.address}/image`,
{
method: 'POST',
From 132a1a4f7c59f57ba0c146ca40a67e9ae9e62ac4 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 10 Jun 2024 12:15:32 +0500
Subject: [PATCH 06/14] ref(profiles): remove upload image type
---
components/profile/create/Modal.vue | 7 +------
services/profile.ts | 4 ----
2 files changed, 1 insertion(+), 10 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 89ff357549..4c680e5ec5 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -34,7 +34,6 @@ import {
} from './stages/index'
import {
CreateProfileRequest,
- ProfileImageType,
SocialLink,
UpdateProfileRequest,
createProfile,
@@ -74,15 +73,13 @@ const close = () => {
const uploadImage = async ({
file,
- type,
address,
}: {
file: File | null
- type: ProfileImageType
address: string
}): Promise =>
file
- ? await uploadProfileImage({ file, address, type }).then((response) =>
+ ? await uploadProfileImage({ file, address }).then((response) =>
getObjectUrl(response.key),
)
: undefined
@@ -112,7 +109,6 @@ const processProfile = async (profileData: ProfileFormData) => {
? await uploadImage({
file: profileData.image,
address: profileData.address,
- type: 'image',
})
: profileData.imagePreview
@@ -120,7 +116,6 @@ const processProfile = async (profileData: ProfileFormData) => {
? await uploadImage({
file: profileData.banner,
address: profileData.address,
- type: 'banner',
})
: profileData.bannerPreview
diff --git a/services/profile.ts b/services/profile.ts
index 2dac91ce9b..ce81cd715c 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -66,12 +66,9 @@ export type UpdateProfileRequest = {
socials: SocialLink[]
}
-export type ProfileImageType = 'image' | 'banner'
-
export type UploadProfileImageRequest = {
address: string
file: File
- type: ProfileImageType
}
export type UploadProfileImageResponse = {
@@ -181,7 +178,6 @@ export const uploadProfileImage = async (
) => {
const form = new FormData()
form.append('file', uploadProfileImage.file)
- form.append('type', uploadProfileImage.type)
try {
const response = await api(
From 17c9a656d9078a09ec1195505092b3cb0983b75b Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 10 Jun 2024 12:17:12 +0500
Subject: [PATCH 07/14] ref(profiles): add safety delay when deleting profile
---
components/profile/create/stages/Form.vue | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/components/profile/create/stages/Form.vue b/components/profile/create/stages/Form.vue
index 5e97ff3fad..d2a1b7f029 100644
--- a/components/profile/create/stages/Form.vue
+++ b/components/profile/create/stages/Form.vue
@@ -105,6 +105,7 @@
v-if="userProfile"
variant="text"
no-shadow
+ :disabled="isDeleteConfirmDisabled"
:class="[deleteConfirm ? '!text-k-red' : '!text-k-grey', 'capitalize']"
@click="deleteProfile">
@@ -168,13 +169,19 @@ const props = defineProps<{
useFarcaster: boolean
}>()
-const deleteConfirm = ref(false)
+const deleteConfirm = ref
()
+const now = useNow()
const { accountId } = useAuth()
const profile = inject<{ userProfile: Ref; hasProfile: Ref }>(
'userProfile',
)
+const isDeleteConfirmDisabled = computed(() =>
+ deleteConfirm.value
+ ? now.value.getTime() - deleteConfirm.value.getTime() < 3000
+ : false,
+)
const substrateAddress = computed(() => formatAddress(accountId.value, 42))
const form = reactive({
address: substrateAddress.value,
@@ -213,7 +220,7 @@ const deleteProfile = () => {
if (deleteConfirm.value) {
emit('delete', substrateAddress.value)
} else {
- deleteConfirm.value = true
+ deleteConfirm.value = new Date()
}
}
From ce7ff6169f0613dbc7ae815fe4eb024f3708f6e8 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 10 Jun 2024 17:57:46 +0500
Subject: [PATCH 08/14] ref(profiles): use image worker to upload images
---
components/profile/create/Modal.vue | 29 +++++---------------
services/imageWorker.ts | 18 +++++++++++++
services/profile.ts | 42 ++---------------------------
3 files changed, 27 insertions(+), 62 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 4c680e5ec5..24dcc714dc 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -38,10 +38,9 @@ import {
UpdateProfileRequest,
createProfile,
deleteProfile,
- getObjectUrl,
updateProfile,
- uploadProfileImage,
} from '@/services/profile'
+import { uploadImage } from '@/services/imageWorker'
import { appClient, createChannel } from '@/services/farcaster'
import { StatusAPIResponse } from '@farcaster/auth-client'
import { useDocumentVisibility } from '@vueuse/core'
@@ -71,18 +70,10 @@ const close = () => {
emit('close')
}
-const uploadImage = async ({
- file,
- address,
-}: {
- file: File | null
- address: string
-}): Promise =>
- file
- ? await uploadProfileImage({ file, address }).then((response) =>
- getObjectUrl(response.key),
- )
- : undefined
+const uploadProfileImage = async (
+ file: File | null,
+): Promise =>
+ file ? await uploadImage(file).then((response) => response.url) : undefined
const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
return [
@@ -106,17 +97,11 @@ const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
const processProfile = async (profileData: ProfileFormData) => {
const imageUrl = profileData.image
- ? await uploadImage({
- file: profileData.image,
- address: profileData.address,
- })
+ ? await uploadProfileImage(profileData.image)
: profileData.imagePreview
const bannerUrl = profileData.banner
- ? await uploadImage({
- file: profileData.banner,
- address: profileData.address,
- })
+ ? await uploadProfileImage(profileData.banner)
: profileData.bannerPreview
const profileBody: CreateProfileRequest | UpdateProfileRequest = {
diff --git a/services/imageWorker.ts b/services/imageWorker.ts
index 266855e097..aba3e1161d 100644
--- a/services/imageWorker.ts
+++ b/services/imageWorker.ts
@@ -40,3 +40,21 @@ export async function getMetadata(url: string) {
return metadata as unknown as NFTWithMetadata
}
+
+export const uploadImage = async (file: File) => {
+ try {
+ const form = new FormData()
+ form.append('file', file)
+
+ workerUrl.pathname = '/image/upload'
+
+ const response = await $fetch<{ url: string }>(workerUrl.toString(), {
+ method: 'POST',
+ body: form,
+ })
+
+ return response
+ } catch (error) {
+ throw new Error(`[IMAGE::UPLOAD] ERROR: ${error?.data}`)
+ }
+}
diff --git a/services/profile.ts b/services/profile.ts
index ce81cd715c..eec722d630 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -9,12 +9,6 @@ const api = $fetch.create({
baseURL: BASE_URL,
})
-const PUBLIC_R2_BUCKET_URL = isProduction
- ? 'https://playground-r2.koda.art'
- : 'https://pub-adc77a8fecb9405b9573442870905a67.r2.dev'
-
-export const getObjectUrl = (key: string) => `${PUBLIC_R2_BUCKET_URL}/${key}`
-
// Types for API request and response objects
export type Profile = {
address: string
@@ -38,15 +32,12 @@ export type SocialLink = {
link: string
}
-type ProfileBaseResponse = {
+export type ProfileResponse = {
success: boolean
message: string
-}
-
-export type ProfileResponse = {
data?: Profile
profileId?: string
-} & ProfileBaseResponse
+}
export type CreateProfileRequest = {
address: string
@@ -66,15 +57,6 @@ export type UpdateProfileRequest = {
socials: SocialLink[]
}
-export type UploadProfileImageRequest = {
- address: string
- file: File
-}
-
-export type UploadProfileImageResponse = {
- key: string
-} & ProfileBaseResponse
-
export type FollowRequest = {
initiatorAddress: string
targetAddress: string
@@ -173,26 +155,6 @@ export const deleteProfile = async (address: string) => {
}
}
-export const uploadProfileImage = async (
- uploadProfileImage: UploadProfileImageRequest,
-) => {
- const form = new FormData()
- form.append('file', uploadProfileImage.file)
-
- try {
- const response = await api(
- `/profiles/${uploadProfileImage.address}/image`,
- {
- method: 'POST',
- body: form,
- },
- )
- return response
- } catch (error) {
- throw new Error(`[PROFILE::FOLLOW] ERROR: ${(error as FetchError).data}`)
- }
-}
-
export const follow = async (followRequest: FollowRequest) => {
try {
const response = await api('/follow', {
From 9ca8c9f216810307070320596b13c1c8c5bf843d Mon Sep 17 00:00:00 2001
From: hassnian
Date: Wed, 12 Jun 2024 12:33:52 +0500
Subject: [PATCH 09/14] add(profiles): add delete profile confirm safety delay
seconds
---
components/profile/create/stages/Form.vue | 68 ++++++++++++++++-------
locales/en.json | 3 +-
2 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/components/profile/create/stages/Form.vue b/components/profile/create/stages/Form.vue
index d2a1b7f029..c152ff3793 100644
--- a/components/profile/create/stages/Form.vue
+++ b/components/profile/create/stages/Form.vue
@@ -101,24 +101,28 @@
data-testid="create-profile-submit-button"
@click="emit('submit', form)" />
-
-
- {{
- !deleteConfirm
- ? $t('profiles.delete')
- : $t('profiles.deleteConfirm')
- }}
-
-
-
-
+
+ {{ deleteConfirmSafetyDelayText }}
+
+
+
+
+ {{ deleteConfirmText }}
+
+
+
+
@@ -160,6 +164,8 @@ const socialLinks = [
},
]
+const DELETE_CONFIRM_SAFETY_DELAY = 3000
+
const emit = defineEmits<{
(e: 'submit', value: ProfileFormData): void
(e: 'delete', address: string): void
@@ -172,16 +178,38 @@ const props = defineProps<{
const deleteConfirm = ref()
const now = useNow()
+const { $i18n } = useNuxtApp()
const { accountId } = useAuth()
const profile = inject<{ userProfile: Ref; hasProfile: Ref }>(
'userProfile',
)
-const isDeleteConfirmDisabled = computed(() =>
+const isDeleteConfirmSafetyDelay = computed(() =>
deleteConfirm.value
- ? now.value.getTime() - deleteConfirm.value.getTime() < 3000
+ ? now.value.getTime() - deleteConfirm.value.getTime() <
+ DELETE_CONFIRM_SAFETY_DELAY
: false,
)
+
+const deleteConfirmSafetyDelayText = computed(() => {
+ if (isDeleteConfirmSafetyDelay.value && deleteConfirm.value) {
+ return $i18n.t('profiles.waitSeconds', [
+ Math.ceil(
+ (deleteConfirm.value.getTime() +
+ DELETE_CONFIRM_SAFETY_DELAY -
+ now.value.getTime()) /
+ 1000,
+ ),
+ ])
+ }
+})
+
+const deleteConfirmText = computed(() =>
+ !deleteConfirm.value
+ ? $i18n.t('profiles.delete')
+ : $i18n.t('profiles.deleteConfirm'),
+)
+
const substrateAddress = computed(() => formatAddress(accountId.value, 42))
const form = reactive({
address: substrateAddress.value,
diff --git a/locales/en.json b/locales/en.json
index 9796833e9e..49305b2cee 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -2093,6 +2093,7 @@
}
},
"delete": "Reset all Fields - start over",
- "deleteConfirm": "You sure? - click again"
+ "deleteConfirm": "You sure? - click again",
+ "waitSeconds": "Wait {0} Seconds"
}
}
From 075780f025e9c936fb3f5b1cd3c74c8a2ab2b99d Mon Sep 17 00:00:00 2001
From: hassnian
Date: Fri, 14 Jun 2024 10:31:09 +0500
Subject: [PATCH 10/14] add(ProfileCreateModal.vue): add profile clear
notification
---
components/profile/create/Modal.vue | 3 +++
locales/en.json | 4 +++-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 24dcc714dc..e9a953c524 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -121,6 +121,9 @@ const processProfile = async (profileData: ProfileFormData) => {
const handleProfileDelete = async (address: string) => {
try {
await deleteProfile(address)
+ infoMessage($i18n.t('profiles.profileHasBeenCleared'), {
+ title: $i18n.t('profiles.profileReset'),
+ })
emit('deleted')
close()
} catch (error) {
diff --git a/locales/en.json b/locales/en.json
index 49305b2cee..d6fa5f0358 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -2094,6 +2094,8 @@
},
"delete": "Reset all Fields - start over",
"deleteConfirm": "You sure? - click again",
- "waitSeconds": "Wait {0} Seconds"
+ "waitSeconds": "Wait {0} Seconds",
+ "profileReset": "Profile Reset",
+ "profileHasBeenCleared": "Your profile has been cleared successfully. Start fresh!"
}
}
From ccc77f10587d4d3e9e0c806fccfd42675ed244b5 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Thu, 20 Jun 2024 11:50:43 +0500
Subject: [PATCH 11/14] update(profiles): upload image with address and type
---
components/profile/create/Modal.vue | 12 +++++++++---
services/imageWorker.ts | 10 +++++++++-
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index b2eee5885d..364e480b0d 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -52,6 +52,7 @@ const props = defineProps<{
const documentVisibility = useDocumentVisibility()
const { $i18n } = useNuxtApp()
+const { accountId } = useAuth()
const profile = inject<{ hasProfile: Ref }>('userProfile')
@@ -73,8 +74,13 @@ const close = () => {
const uploadProfileImage = async (
file: File | null,
+ type: 'image' | 'banner',
): Promise =>
- file ? await uploadImage(file).then((response) => response.url) : undefined
+ file
+ ? await uploadImage({ file, type, address: accountId.value }).then(
+ (response) => response.url,
+ )
+ : undefined
const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
return [
@@ -98,11 +104,11 @@ const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
const processProfile = async (profileData: ProfileFormData) => {
const imageUrl = profileData.image
- ? await uploadProfileImage(profileData.image)
+ ? await uploadProfileImage(profileData.image, 'image')
: profileData.imagePreview
const bannerUrl = profileData.banner
- ? await uploadProfileImage(profileData.banner)
+ ? await uploadProfileImage(profileData.banner, 'banner')
: profileData.bannerPreview
const profileBody: CreateProfileRequest | UpdateProfileRequest = {
diff --git a/services/imageWorker.ts b/services/imageWorker.ts
index aba3e1161d..836fd2c1c8 100644
--- a/services/imageWorker.ts
+++ b/services/imageWorker.ts
@@ -41,10 +41,18 @@ export async function getMetadata(url: string) {
return metadata as unknown as NFTWithMetadata
}
-export const uploadImage = async (file: File) => {
+type UploadImage = {
+ file: File
+ type: string
+ address: string
+}
+
+export const uploadImage = async ({ file, type, address }: UploadImage) => {
try {
const form = new FormData()
form.append('file', file)
+ form.append('address', address)
+ form.append('type', type)
workerUrl.pathname = '/image/upload'
From 66c7d2c635f0fa458e1bee040d9b8822b268c77a Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 1 Jul 2024 09:45:35 +0500
Subject: [PATCH 12/14] ref(profiles): add upload image
---
components/profile/create/Modal.vue | 25 ++-
pnpm-lock.yaml | 226 ++++++++++++++--------------
services/imageWorker.ts | 26 ----
services/profile.ts | 38 +++++
4 files changed, 172 insertions(+), 143 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 2d0b41714f..834bf16c6b 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -39,8 +39,8 @@ import {
createProfile,
deleteProfile,
updateProfile,
+ uploadImage,
} from '@/services/profile'
-import { uploadImage } from '@/services/imageWorker'
import { appClient, createChannel } from '@/services/farcaster'
import { StatusAPIResponse } from '@farcaster/auth-client'
import { useDocumentVisibility } from '@vueuse/core'
@@ -75,12 +75,23 @@ const close = () => {
const uploadProfileImage = async (
file: File | null,
type: 'image' | 'banner',
-): Promise =>
- file
- ? await uploadImage({ file, type, address: accountId.value }).then(
- (response) => response.url,
- )
- : undefined
+): Promise => {
+ if (!file) {
+ return undefined
+ }
+
+ const { signature, message } = await getSignaturePair()
+
+ const response = await uploadImage({
+ file,
+ type,
+ address: accountId.value,
+ signature,
+ message,
+ })
+
+ return response.url
+}
const constructSocials = (profileData: ProfileFormData): SocialLink[] => {
return [
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index bdbee09c50..28fc5dfd6d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,4 +1,4 @@
-lockfileVersion: '6.0'
+lockfileVersion: '6.1'
settings:
autoInstallPeers: true
@@ -3844,7 +3844,7 @@ packages:
resolution: {integrity: sha512-yyHHAj4G8pQIDfaIsMvQpwKMboIZtcHTUvPqXjOHyldh1O1vZfH4W03VDPv5RvI9P6DLTzJQlmVgj9wCf7c2Fw==}
peerDependencies:
'@fortawesome/fontawesome-svg-core': ~1 || ~6
- vue: 3.4.8
+ vue: '>= 3.0.0 < 4'
dependencies:
'@fortawesome/fontawesome-svg-core': 6.5.2
vue: 3.4.8(typescript@5.4.5)
@@ -3963,7 +3963,7 @@ packages:
resolution: {integrity: sha512-DVGoYXPDcoJ55crD4cAXA0OGAS8fWHvKjvOApY1NLLN4DgRjxqHBVE6xCX/9Ai1VTM3izG6FJgXiXAbRVgv5KQ==}
peerDependencies:
histoire: ^0.17.6
- vue: 3.4.8
+ vue: ^3.2.47
dependencies:
'@histoire/controls': 0.17.15(vite@4.5.3)
'@histoire/shared': 0.17.15(vite@4.5.3)
@@ -4580,7 +4580,7 @@ packages:
qr-code-styling: 1.6.0-rc.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-i18next: 13.5.0(i18next@22.5.1)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0)
+ react-i18next: 13.5.0(i18next@23.11.5)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0)
react-native: 0.74.1(@babel/core@7.24.7)(@babel/preset-env@7.24.4)(react@18.2.0)
dev: false
@@ -4604,7 +4604,7 @@ packages:
qr-code-styling: 1.6.0-rc.1
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- react-i18next: 13.5.0(i18next@22.5.1)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0)
+ react-i18next: 13.5.0(i18next@23.11.5)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0)
react-native: 0.74.1(@babel/core@7.24.7)(@babel/preset-env@7.24.4)(react@18.2.0)
dev: false
@@ -5613,7 +5613,7 @@ packages:
resolution: {integrity: sha512-gE7bKxbnd3OdlCHdZKgnbs2oOdcLHvEQ92LGnDCs9rCdsXazhQ7gcfow+FsKMp9MMu785O55gd4CiIgnn7N0BA==}
engines: {node: ^14.18.0 || >=16.10.0}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.3.4
dependencies:
'@nuxt/kit': 3.12.2(magicast@0.3.4)(rollup@4.14.0)
'@rollup/plugin-replace': 5.0.7(rollup@4.14.0)
@@ -5906,7 +5906,7 @@ packages:
/@oruga-ui/oruga-next@0.7.0(vue@3.4.8):
resolution: {integrity: sha512-T2KnNhGzgqv/Xzu4Efx3wnYahANcP6Z7Yc8DHOFIOLrM+ZDdTS9OjL3gofBVDrDBRg1DQv6EvsSsNkwMR88LpA==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
vue: 3.4.8(typescript@5.4.5)
dev: true
@@ -6270,15 +6270,15 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/api-augment@11.3.1:
- resolution: {integrity: sha512-Yj+6rb6h0WwY3yJ+UGhjGW+tyMRFUMsKQuGw+eFsXdjiNU9UoXsAqA2dG7Q1F+oeX/g+y2gLGBezNoCwbl6HfA==}
+ /@polkadot/api-augment@12.0.2:
+ resolution: {integrity: sha512-l/0yoyhSWtHGkyrJvY9Pw78b8j0Now8f/4G4A2maeBL2U4OBjbGzwykPHpfTKeRfiulsUi408e6iWN94AjXxLA==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/api-base': 11.3.1
- '@polkadot/rpc-augment': 11.3.1
- '@polkadot/types': 11.3.1
- '@polkadot/types-augment': 11.3.1
- '@polkadot/types-codec': 11.3.1
+ '@polkadot/api-base': 12.0.2
+ '@polkadot/rpc-augment': 12.0.2
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-augment': 12.0.2
+ '@polkadot/types-codec': 12.0.2
'@polkadot/util': 12.6.2
tslib: 2.6.2
transitivePeerDependencies:
@@ -6350,12 +6350,12 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/api-base@11.3.1:
- resolution: {integrity: sha512-b8UkNL00NN7+3QaLCwL5cKg+7YchHoKCAhwKusWHNBZkkO6Oo2BWilu0dZkPJOyqV9P389Kbd9+oH+SKs9u2VQ==}
+ /@polkadot/api-base@12.0.2:
+ resolution: {integrity: sha512-LAaI6iyzlefrzJpEQb0YYtD1P9m9Hgx1iQY+Cov1uZzw6MYIlBQBBrbGzPS96NC7UxMSoeIv7GDMRPk/HCHf0A==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/rpc-core': 11.3.1
- '@polkadot/types': 11.3.1
+ '@polkadot/rpc-core': 12.0.2
+ '@polkadot/types': 12.0.2
'@polkadot/util': 12.6.2
rxjs: 7.8.1
tslib: 2.6.2
@@ -6434,16 +6434,16 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/api-derive@11.3.1:
- resolution: {integrity: sha512-9dopzrh4cRuft1nANmBvMY/hEhFDu0VICMTOGxQLOl8NMfcOFPTLAN0JhSBUoicGZhV+c4vpv01NBx/7/IL1HA==}
+ /@polkadot/api-derive@12.0.2:
+ resolution: {integrity: sha512-i3AnOSHLw7DNLd+byxekQQxKRWseZANZnyg2F29kVBBDu6Fy7G6UaE2zPZaxS7w6wSqmTeB1u86WSvRocjkETw==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/api': 11.3.1
- '@polkadot/api-augment': 11.3.1
- '@polkadot/api-base': 11.3.1
- '@polkadot/rpc-core': 11.3.1
- '@polkadot/types': 11.3.1
- '@polkadot/types-codec': 11.3.1
+ '@polkadot/api': 12.0.2
+ '@polkadot/api-augment': 12.0.2
+ '@polkadot/api-base': 12.0.2
+ '@polkadot/rpc-core': 12.0.2
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-codec': 12.0.2
'@polkadot/util': 12.6.2
'@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2)
rxjs: 7.8.1
@@ -6547,22 +6547,22 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/api@11.3.1:
- resolution: {integrity: sha512-q4kFIIHTLvKxM24b0Eo8hJevsPMme+aITJGrDML9BgdZYTRN14+cu5nXiCsQvaEamdyYj+uCXWe2OV9X7pPxsA==}
+ /@polkadot/api@12.0.2:
+ resolution: {integrity: sha512-6JSCQ8scZNETos07CGoP8WehoEUDmXgRxWn4ce9O1kn/j5i6xCZj/dLp3/OPfh5ERYvVELRZr90bxUglckPj8w==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/api-augment': 11.3.1
- '@polkadot/api-base': 11.3.1
- '@polkadot/api-derive': 11.3.1
+ '@polkadot/api-augment': 12.0.2
+ '@polkadot/api-base': 12.0.2
+ '@polkadot/api-derive': 12.0.2
'@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2)
- '@polkadot/rpc-augment': 11.3.1
- '@polkadot/rpc-core': 11.3.1
- '@polkadot/rpc-provider': 11.3.1
- '@polkadot/types': 11.3.1
- '@polkadot/types-augment': 11.3.1
- '@polkadot/types-codec': 11.3.1
- '@polkadot/types-create': 11.3.1
- '@polkadot/types-known': 11.3.1
+ '@polkadot/rpc-augment': 12.0.2
+ '@polkadot/rpc-core': 12.0.2
+ '@polkadot/rpc-provider': 12.0.2
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-augment': 12.0.2
+ '@polkadot/types-codec': 12.0.2
+ '@polkadot/types-create': 12.0.2
+ '@polkadot/types-known': 12.0.2
'@polkadot/util': 12.6.2
'@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2)
eventemitter3: 5.0.1
@@ -6902,13 +6902,13 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/rpc-augment@11.3.1:
- resolution: {integrity: sha512-2PaDcKNju4QYQpxwVkWbRU3M0t340nMX9cMo+8awgvgL1LliV/fUDZueMKLuSS910JJMTPQ7y2pK4eQgMt08gQ==}
+ /@polkadot/rpc-augment@12.0.2:
+ resolution: {integrity: sha512-aQ4j3ifvT+co2tkMSS4iEdNhCunTtObXD1r2+jS9iLz0d8IrpXr6fZ1FzLuM5s3ijh8QpFBHiAs514+Wj9TNww==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/rpc-core': 11.3.1
- '@polkadot/types': 11.3.1
- '@polkadot/types-codec': 11.3.1
+ '@polkadot/rpc-core': 12.0.2
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-codec': 12.0.2
'@polkadot/util': 12.6.2
tslib: 2.6.2
transitivePeerDependencies:
@@ -6978,13 +6978,13 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/rpc-core@11.3.1:
- resolution: {integrity: sha512-KKNepsDd/mpmXcA6v/h14eFFPEzLGd7nrvx2UUXUxoZ0Fq2MH1hplP3s93k1oduNY/vOXJR2K9S4dKManA6GVQ==}
+ /@polkadot/rpc-core@12.0.2:
+ resolution: {integrity: sha512-lizSfchCaBjvNRZG7gELy3HKvvrLqLC4sMBg/1Y0zcsyZork8MxBkcVKgHQGBJ5BWLaoRrRKESC5DLe7DzZ2fA==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/rpc-augment': 11.3.1
- '@polkadot/rpc-provider': 11.3.1
- '@polkadot/types': 11.3.1
+ '@polkadot/rpc-augment': 12.0.2
+ '@polkadot/rpc-provider': 12.0.2
+ '@polkadot/types': 12.0.2
'@polkadot/util': 12.6.2
rxjs: 7.8.1
tslib: 2.6.2
@@ -7097,13 +7097,13 @@ packages:
- utf-8-validate
dev: false
- /@polkadot/rpc-provider@11.3.1:
- resolution: {integrity: sha512-pqERChoHo45hd3WAgW8UuzarRF+G/o/eXEbl0PXLubiayw4X4qCmIzmtntUcKYgxGNcYGZaG87ZU8OjN97m6UA==}
+ /@polkadot/rpc-provider@12.0.2:
+ resolution: {integrity: sha512-WyQ9MxTYFAn0EH+2+2ZpzNwEFbnlCDedTW9bzrqGhT3RofYGfX/tpHzgQAyC4FSiCFA001gbwqskfDjVfpdy3A==}
engines: {node: '>=18'}
dependencies:
'@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2)
- '@polkadot/types': 11.3.1
- '@polkadot/types-support': 11.3.1
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-support': 12.0.2
'@polkadot/util': 12.6.2
'@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2)
'@polkadot/x-fetch': 12.6.2
@@ -7197,12 +7197,12 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types-augment@11.3.1:
- resolution: {integrity: sha512-eR3HVpvUmB3v7q2jTWVmVfAVfb1/kuNn7ij94Zqadg/fuUq0pKqIOKwkUj3OxRM3A/5BnW3MbgparjKD3r+fyw==}
+ /@polkadot/types-augment@12.0.2:
+ resolution: {integrity: sha512-vCDqcuVBTr2PTFf2YNolt/hbNx9sC3xzeYtGsYeBV7QfiljI324P0yLH1oeunFrIgI+G6OxiL4DIJcXzlyXEPQ==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/types': 11.3.1
- '@polkadot/types-codec': 11.3.1
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-codec': 12.0.2
'@polkadot/util': 12.6.2
tslib: 2.6.2
dev: false
@@ -7254,8 +7254,8 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types-codec@11.3.1:
- resolution: {integrity: sha512-i7IiiuuL+Z/jFoKTA9xeh4wGQnhnNNjMT0+1ohvlOvnFsoKZKFQQOaDPPntGJVL1JDCV+KjkN2uQKZSeW8tguQ==}
+ /@polkadot/types-codec@12.0.2:
+ resolution: {integrity: sha512-W86PRqQf/8NW16+QszocizA1DbKwjMcbdecQJU57rbg340JuVMooDxaGuW6S2nRUFKwyVEmwVolDXUOYJcp8Vw==}
engines: {node: '>=18'}
dependencies:
'@polkadot/util': 12.6.2
@@ -7307,11 +7307,11 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types-create@11.3.1:
- resolution: {integrity: sha512-pBXtpz5FehcRJ6j5MzFUIUN8ZWM7z6HbqK1GxBmYbJVRElcGcOg7a/rL2pQVphU0Rx1E8bSO4thzGf4wUxSX7w==}
+ /@polkadot/types-create@12.0.2:
+ resolution: {integrity: sha512-2spRoI5PqezBXU3BFEwtvm6m/jwqmUzT2px0FIq8YZYzNWgmkew+oDAft89MXV+wGqutyO4BlASUGy5d3C6XNw==}
engines: {node: '>=18'}
dependencies:
- '@polkadot/types-codec': 11.3.1
+ '@polkadot/types-codec': 12.0.2
'@polkadot/util': 12.6.2
tslib: 2.6.2
dev: false
@@ -7358,14 +7358,14 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types-known@11.3.1:
- resolution: {integrity: sha512-3BIof7u6tn9bk3ZCIxA07iNoQ3uj4+vn3DTOjCKECozkRlt6V+kWRvqh16Hc0SHMg/QjcMb2fIu/WZhka1McUQ==}
+ /@polkadot/types-known@12.0.2:
+ resolution: {integrity: sha512-9Au2gVyjLXIJSoFzLs9eQdP5Z1L0J4ezTLWvUGZ5gQYhi19WViSUVYMDVn1wYJpYbHtVX6ee0XqyLQGcohCHDg==}
engines: {node: '>=18'}
dependencies:
'@polkadot/networks': 12.6.2
- '@polkadot/types': 11.3.1
- '@polkadot/types-codec': 11.3.1
- '@polkadot/types-create': 11.3.1
+ '@polkadot/types': 12.0.2
+ '@polkadot/types-codec': 12.0.2
+ '@polkadot/types-create': 12.0.2
'@polkadot/util': 12.6.2
tslib: 2.6.2
dev: false
@@ -7438,8 +7438,8 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types-support@11.3.1:
- resolution: {integrity: sha512-jTFz1GKyF7nI29yIOq4v0NiWTOf5yX4HahJNeFD8TcxoLhF+6tH/XXqrUXJEfbaTlSrRWiW1LZYlb+snctqKHA==}
+ /@polkadot/types-support@12.0.2:
+ resolution: {integrity: sha512-RhVoHJvxhnlhxt1asa9W3gExZpwSJkRb9YXVAoRdx1zk920j+PzJfBv/OTEaXgtHcIUrbVbddJtyMEOlNMMVdA==}
engines: {node: '>=18'}
dependencies:
'@polkadot/util': 12.6.2
@@ -7504,14 +7504,14 @@ packages:
tslib: 2.6.2
dev: false
- /@polkadot/types@11.3.1:
- resolution: {integrity: sha512-5c7uRFXQTT11Awi6T0yFIdAfD6xGDAOz06Kp7M5S9OGNZY28wSPk5x6BYfNphWPaIBmHHewYJB5qmnrdYQAWKQ==}
+ /@polkadot/types@12.0.2:
+ resolution: {integrity: sha512-qjbmu8p1qoueZak+kTdI6zKuRB4DIDA3bTWsHTmgeoWlZrSHcTJuYq8VjGDete+1S2+ZqEiVYXB4+CEzWQeehA==}
engines: {node: '>=18'}
dependencies:
'@polkadot/keyring': 12.6.2(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2)
- '@polkadot/types-augment': 11.3.1
- '@polkadot/types-codec': 11.3.1
- '@polkadot/types-create': 11.3.1
+ '@polkadot/types-augment': 12.0.2
+ '@polkadot/types-codec': 12.0.2
+ '@polkadot/types-create': 12.0.2
'@polkadot/util': 12.6.2
'@polkadot/util-crypto': 12.6.2(@polkadot/util@12.6.2)
rxjs: 7.8.1
@@ -7752,7 +7752,7 @@ packages:
peerDependencies:
'@polkadot/util': '*'
'@polkadot/util-crypto': '*'
- vue: 3.4.8
+ vue: '>= 2.7'
dependencies:
'@polkadot/ui-shared': 3.6.6(@polkadot/util-crypto@12.6.2)(@polkadot/util@12.6.2)
'@polkadot/util': 12.6.2
@@ -9397,7 +9397,7 @@ packages:
/@subsocial/definitions@0.8.14:
resolution: {integrity: sha512-K/8ZYGMyy15QI16bxgi0GfxP3JsnKeNAyPlwom1kDE89RGGs5O++PuWbXxVMMSVYfh9zn9qJYKiThBYIj/Vohg==}
dependencies:
- '@polkadot/api': 11.3.1
+ '@polkadot/api': 12.0.2
lodash.camelcase: 4.3.0
transitivePeerDependencies:
- bufferutil
@@ -9575,7 +9575,7 @@ packages:
resolution: {integrity: sha512-WogAH4+xDPWbiK9CUXAE4cQiCyvWeYZI3g3/onKbkb3tVnoEPRhbGHANgxpfAEFY165Vj4afKnI3hkVQvr7aHA==}
peerDependencies:
'@vue/composition-api': ^1.1.2
- vue: 3.4.8
+ vue: ^2.6.0 || ^3.3.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -10360,7 +10360,7 @@ packages:
/@unhead/vue@1.9.14(vue@3.4.8):
resolution: {integrity: sha512-Yc7Qv0ze+iLte4urHiA+ghkF7y+svrawrT+ZrCuGXkZ/eRTF/AY2SKex+rJQJZsP+fKEQ2pGb72IsI5kHFZT3A==}
peerDependencies:
- vue: 3.4.8
+ vue: '>=2.7 || >=3'
dependencies:
'@unhead/schema': 1.9.14
'@unhead/shared': 1.9.14
@@ -10372,7 +10372,7 @@ packages:
/@unhead/vue@1.9.4(vue@3.4.8):
resolution: {integrity: sha512-F37bDhhieWQJyXvFV8NmrOXoIVJMhxVI/0ZUDrI9uTkMCofjfKWDJ+Gz0iYdhYF9mjQ5BN+pM31Zpxi+fN5Cfg==}
peerDependencies:
- vue: 3.4.8
+ vue: '>=2.7 || >=3'
dependencies:
'@unhead/schema': 1.9.4
'@unhead/shared': 1.9.4
@@ -10726,7 +10726,7 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
vite: ^5.0.0
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
'@babel/core': 7.24.7
'@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7)
@@ -10742,7 +10742,7 @@ packages:
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.0.0 || ^5.0.0
- vue: 3.4.8
+ vue: ^3.2.25
dependencies:
vite: 4.5.3(@types/node@20.14.6)(sass@1.77.6)
vue: 3.4.8(typescript@5.4.5)
@@ -10753,7 +10753,7 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
vite: ^5.0.0
- vue: 3.4.8
+ vue: ^3.2.25
dependencies:
vite: 5.3.1(@types/node@20.14.6)(sass@1.77.6)
vue: 3.4.8(typescript@5.4.5)
@@ -10882,7 +10882,7 @@ packages:
resolution: {integrity: sha512-WC66NPVh2mJWqm4L0l/u/cOqm4pNOIwVdMGnDYAH2rHcOWy5x68GkhpkYTBu1+xwCSeHWOQn1TCGGbD+98fFpA==}
engines: {node: '>=16.14.0'}
peerDependencies:
- vue: 3.4.8
+ vue: ^2.7.0 || ^3.2.25
peerDependenciesMeta:
vue:
optional: true
@@ -10904,7 +10904,7 @@ packages:
'@apollo/client': ^3.4.13
'@vue/composition-api': ^1.0.0
graphql: '>=15'
- vue: 3.4.8
+ vue: ^2.6.0 || ^3.1.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -11090,7 +11090,7 @@ packages:
/@vue/devtools-applet@7.1.3(@unocss/reset@0.60.2)(floating-vue@5.2.2)(unocss@0.60.2)(vite@5.3.1)(vue@3.4.8):
resolution: {integrity: sha512-525h17FzUF7ssko/U+yeP5jv0HaGm3eI4dVqncWPRCLTDtOy1V+srjoxYqr5qnzx6AdIU2icPQF2KNomd9FGZw==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
'@vue/devtools-core': 7.1.3(vite@5.3.1)(vue@3.4.8)
'@vue/devtools-kit': 7.1.3(vue@3.4.8)
@@ -11138,7 +11138,7 @@ packages:
/@vue/devtools-kit@7.1.3(vue@3.4.8):
resolution: {integrity: sha512-NFskFSJMVCBXTkByuk2llzI3KD3Blcm7WqiRorWjD6nClHPgkH5BobDH08rfulqq5ocRt5xV+3qOT1Q9FXJrwQ==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
'@vue/devtools-shared': 7.1.3
hookable: 5.5.3
@@ -11160,7 +11160,7 @@ packages:
'@unocss/reset': '>=0.50.0-0'
floating-vue: '>=2.0.0-0'
unocss: '>=0.50.0-0'
- vue: 3.4.8
+ vue: '>=3.0.0-0'
dependencies:
'@unocss/reset': 0.60.2
'@vue/devtools-shared': 7.1.3
@@ -11283,7 +11283,7 @@ packages:
/@vueuse/head@2.0.0(vue@3.4.8):
resolution: {integrity: sha512-ykdOxTGs95xjD4WXE4na/umxZea2Itl0GWBILas+O4oqS7eXIods38INvk3XkJKjqMdWPcpCyLX/DioLQxU1KA==}
peerDependencies:
- vue: 3.4.8
+ vue: '>=2.7 || >=3'
dependencies:
'@unhead/dom': 1.9.4
'@unhead/schema': 1.9.4
@@ -12274,7 +12274,7 @@ packages:
/@web3modal/scaffold-vue@4.2.2(react@18.2.0)(vue@3.4.8):
resolution: {integrity: sha512-oaxOyaG5enjodIp/FNyodIPiFa3yiB4ptQrRfNX5opv6z2HUKDiu4jM3BRLwys2ncgLSflhDGfx3QQZZqNR8Hg==}
peerDependencies:
- vue: 3.4.8
+ vue: '>=3'
peerDependenciesMeta:
vue:
optional: true
@@ -12370,7 +12370,7 @@ packages:
react: '>=17'
react-dom: '>=17'
viem: '>=2.0.0'
- vue: 3.4.8
+ vue: '>=3'
peerDependenciesMeta:
react:
optional: true
@@ -16015,7 +16015,7 @@ packages:
resolution: {integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==}
peerDependencies:
'@nuxt/kit': ^3.2.0
- vue: 3.4.8
+ vue: ^3.2.0
peerDependenciesMeta:
'@nuxt/kit':
optional: true
@@ -16944,6 +16944,12 @@ packages:
'@babel/runtime': 7.24.4
dev: false
+ /i18next@23.11.5:
+ resolution: {integrity: sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==}
+ dependencies:
+ '@babel/runtime': 7.24.4
+ dev: false
+
/iconv-lite@0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
@@ -20711,7 +20717,7 @@ packages:
peerDependencies:
'@vue/composition-api': ^1.4.0
typescript: '>=4.4.4'
- vue: 3.4.8
+ vue: ^2.6.14 || ^3.3.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -21724,7 +21730,7 @@ packages:
/qrcode.vue@3.4.1(vue@3.4.8):
resolution: {integrity: sha512-wq/zHsifH4FJ1GXQi8/wNxD1KfQkckIpjK1KPTc/qwYU5/Bkd4me0w4xZSg6EXk6xLBkVDE0zxVagewv5EMAVA==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
vue: 3.4.8(typescript@5.4.5)
dev: false
@@ -21854,7 +21860,7 @@ packages:
scheduler: 0.23.0
dev: false
- /react-i18next@13.5.0(i18next@22.5.1)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0):
+ /react-i18next@13.5.0(i18next@23.11.5)(react-dom@18.2.0)(react-native@0.74.1)(react@18.2.0):
resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==}
peerDependencies:
i18next: '>= 23.2.3'
@@ -21869,7 +21875,7 @@ packages:
dependencies:
'@babel/runtime': 7.24.4
html-parse-stringify: 3.0.1
- i18next: 22.5.1
+ i18next: 23.11.5
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-native: 0.74.1(@babel/core@7.24.7)(@babel/preset-env@7.24.4)(react@18.2.0)
@@ -22863,7 +22869,7 @@ packages:
/site-config-stack@2.2.12(vue@3.4.8):
resolution: {integrity: sha512-U+nyw2vZ6E2zF/JYlFFEmDsqXSJbf0/6ZBCKXI4FZ2509iQwnEesfQXvWNuJ2JCemUJdAXAoiIturxEJtV4z0g==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3
dependencies:
ufo: 1.5.3
vue: 3.4.8(typescript@5.4.5)
@@ -24708,7 +24714,7 @@ packages:
'@vue/composition-api': ^1.0.0-rc.1
typescript: '>=5.0.4'
viem: 2.x
- vue: 3.4.8
+ vue: ^2.0.0 || >=3.0.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -25118,7 +25124,7 @@ packages:
/vite-svg-loader@5.1.0(vue@3.4.8):
resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
peerDependencies:
- vue: 3.4.8
+ vue: '>=3.2.13'
dependencies:
svgo: 3.2.0
vue: 3.4.8(typescript@5.4.5)
@@ -25427,7 +25433,7 @@ packages:
resolution: {integrity: sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==}
peerDependencies:
chart.js: ^4.1.1
- vue: 3.4.8
+ vue: ^3.0.0-0 || ^2.7.0
dependencies:
chart.js: 4.4.3
vue: 3.4.8(typescript@5.4.5)
@@ -25440,7 +25446,7 @@ packages:
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
- vue: 3.4.8
+ vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -25455,7 +25461,7 @@ packages:
requiresBuild: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
- vue: 3.4.8
+ vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
@@ -25469,7 +25475,7 @@ packages:
/vue-dompurify-html@4.1.4(vue@3.4.8):
resolution: {integrity: sha512-K0XDSZA4dmMMvAgW8yaCx1kAYQldmgXeHJaLPS0mlSKOu8B+onE06X4KfB5LGyX4jR3rlVosyWJczRBzR0sZ/g==}
peerDependencies:
- vue: 3.4.8
+ vue: ^2.7.0 || ^3.0.0
dependencies:
dompurify: 3.0.11
vue: 3.4.8(typescript@5.4.5)
@@ -25518,7 +25524,7 @@ packages:
resolution: {integrity: sha512-vU4gY6lu8Pdfs9BgKGiDAJmFDf88cceR47KcSB0VW4xJzUrXR/7qwqM7A8dQ2nedhoIDxoOm5Ro4pFd2KvJqbA==}
engines: {node: '>= 16'}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
'@intlify/core-base': 9.11.0
'@intlify/shared': 9.11.0
@@ -25529,7 +25535,7 @@ packages:
/vue-observe-visibility@2.0.0-alpha.1(vue@3.4.8):
resolution: {integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
vue: 3.4.8(typescript@5.4.5)
dev: true
@@ -25537,7 +25543,7 @@ packages:
/vue-resize@2.0.0-alpha.1(vue@3.4.8):
resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.0.0
dependencies:
vue: 3.4.8(typescript@5.4.5)
dev: true
@@ -25545,7 +25551,7 @@ packages:
/vue-router@4.3.0(vue@3.4.8):
resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.2.0
dependencies:
'@vue/devtools-api': 6.6.1
vue: 3.4.8(typescript@5.4.5)
@@ -25554,7 +25560,7 @@ packages:
/vue-router@4.3.3(vue@3.4.8):
resolution: {integrity: sha512-8Q+u+WP4N2SXY38FDcF2H1dUEbYVHVPtPCPZj/GTZx8RCbiB8AtJP9+YIxn4Vs0svMTNQcLIzka4GH7Utkx9xQ==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.2.0
dependencies:
'@vue/devtools-api': 6.6.1
vue: 3.4.8(typescript@5.4.5)
@@ -25570,7 +25576,7 @@ packages:
/vue-tippy@6.4.1(vue@3.4.8):
resolution: {integrity: sha512-PEAKdioZjUvYWz4euxHFSXKJbL6kIKO29/LtQaCBbnd5Vg0U5kL8iLuqRshB2I31pXPSQS0qJsWx56178eS2QA==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.2.0
dependencies:
tippy.js: 6.3.7
vue: 3.4.8(typescript@5.4.5)
@@ -25579,7 +25585,7 @@ packages:
/vue-virtual-scroller@2.0.0-beta.8(vue@3.4.8):
resolution: {integrity: sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==}
peerDependencies:
- vue: 3.4.8
+ vue: ^3.2.0
dependencies:
mitt: 2.1.0
vue: 3.4.8(typescript@5.4.5)
@@ -25591,7 +25597,7 @@ packages:
resolution: {integrity: sha512-0KEU+t1ZcOFomf2xhpKPMU2XBdZDVyVjvkxcXAJRpZ818Om4MMhKxbrmIK6hZ+NZOyoRAgMHl/N1zFZJuQoSJA==}
engines: {node: '>=14.6'}
peerDependencies:
- vue: 3.4.8
+ vue: '>=3.0.0'
dependencies:
vue: 3.4.8(typescript@5.4.5)
dev: false
diff --git a/services/imageWorker.ts b/services/imageWorker.ts
index 836fd2c1c8..266855e097 100644
--- a/services/imageWorker.ts
+++ b/services/imageWorker.ts
@@ -40,29 +40,3 @@ export async function getMetadata(url: string) {
return metadata as unknown as NFTWithMetadata
}
-
-type UploadImage = {
- file: File
- type: string
- address: string
-}
-
-export const uploadImage = async ({ file, type, address }: UploadImage) => {
- try {
- const form = new FormData()
- form.append('file', file)
- form.append('address', address)
- form.append('type', type)
-
- workerUrl.pathname = '/image/upload'
-
- const response = await $fetch<{ url: string }>(workerUrl.toString(), {
- method: 'POST',
- body: form,
- })
-
- return response
- } catch (error) {
- throw new Error(`[IMAGE::UPLOAD] ERROR: ${error?.data}`)
- }
-}
diff --git a/services/profile.ts b/services/profile.ts
index 44f65ce17f..6dec93f23e 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -224,3 +224,41 @@ export const isFollowing = async (
)
}
}
+
+type UploadImage = {
+ file: File
+ type: string
+ address: string
+ signature: string
+ message: string
+}
+
+export const uploadImage = async ({
+ file,
+ type,
+ address,
+ signature,
+ message,
+}: UploadImage) => {
+ try {
+ address = toSubstrateAddress(address)
+
+ const form = new FormData()
+ form.append('file', file)
+ form.append('address', address)
+ form.append('type', type)
+ form.append('signature', signature)
+ form.append('message', message)
+
+ const response = await api<{ url: string }>(`/profiles/${address}/image`, {
+ method: 'POST',
+ body: form,
+ })
+
+ return response
+ } catch (error) {
+ throw new Error(
+ `[PROFILE::UPLOAD_IMAGe] ERROR: ${(error as FetchError).data}`,
+ )
+ }
+}
From e5b10f3b079581179f11ff013a17d43eb9402238 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 1 Jul 2024 09:55:16 +0500
Subject: [PATCH 13/14] fix(profiles): delete profile missing signature
---
components/profile/create/Modal.vue | 3 ++-
services/profile.ts | 17 ++++++++++++++++-
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/components/profile/create/Modal.vue b/components/profile/create/Modal.vue
index 834bf16c6b..28a892d464 100644
--- a/components/profile/create/Modal.vue
+++ b/components/profile/create/Modal.vue
@@ -144,7 +144,8 @@ const processProfile = async (profileData: ProfileFormData) => {
const handleProfileDelete = async (address: string) => {
try {
- await deleteProfile(address)
+ const { signature, message } = await getSignaturePair()
+ await deleteProfile({ address, message, signature })
infoMessage($i18n.t('profiles.profileHasBeenCleared'), {
title: $i18n.t('profiles.profileReset'),
})
diff --git a/services/profile.ts b/services/profile.ts
index 6dec93f23e..507e6129b7 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -165,10 +165,25 @@ export const updateProfile = async (updates: UpdateProfileRequest) => {
}
}
-export const deleteProfile = async (address: string) => {
+type DeleteProfile = {
+ message: string
+ signature: string
+ address: string
+}
+
+export const deleteProfile = async ({
+ address,
+ message,
+ signature,
+}: DeleteProfile) => {
try {
const response = await api(`/profiles/${address}`, {
method: 'DELETE',
+ body: {
+ message,
+ signature,
+ address,
+ },
})
return response
} catch (error) {
From dffdc13c59eace1b69f4c37bdb90ee988b9eec99 Mon Sep 17 00:00:00 2001
From: hassnian
Date: Mon, 1 Jul 2024 09:59:03 +0500
Subject: [PATCH 14/14] fix(profiles): image upload throw error typo
---
services/profile.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/services/profile.ts b/services/profile.ts
index 507e6129b7..2ecb3a5683 100644
--- a/services/profile.ts
+++ b/services/profile.ts
@@ -273,7 +273,7 @@ export const uploadImage = async ({
return response
} catch (error) {
throw new Error(
- `[PROFILE::UPLOAD_IMAGe] ERROR: ${(error as FetchError).data}`,
+ `[PROFILE::UPLOAD_IMAGE] ERROR: ${(error as FetchError).data}`,
)
}
}