Commit 2f4c6b6d authored by tom's avatar tom

public tags resource

parent efc37fa9
...@@ -12,6 +12,9 @@ export const RESOURCES = { ...@@ -12,6 +12,9 @@ export const RESOURCES = {
watchlist: { watchlist: {
path: '/api/account/v1/user/watchlist/:id?', path: '/api/account/v1/user/watchlist/:id?',
}, },
public_tags: {
path: '/api/account/v1/user/public_tags/:id?',
},
// DEPRECATED // DEPRECATED
old_api: { old_api: {
...@@ -27,3 +30,5 @@ export interface ResourceError<T = unknown> { ...@@ -27,3 +30,5 @@ export interface ResourceError<T = unknown> {
status: Response['status']; status: Response['status'];
statusText: Response['statusText']; statusText: Response['statusText'];
} }
export type ResourceErrorAccount<T> = ResourceError<{ errors: T }>
import type { UseQueryOptions } from '@tanstack/react-query'; import type { UseQueryOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import type { UserInfo, CustomAbis } from 'types/api/account'; import type { UserInfo, CustomAbis, PublicTags } from 'types/api/account';
import type { CsrfData } from 'types/client/account'; import type { CsrfData } from 'types/client/account';
import type { RESOURCES, ResourceError } from './resources'; import type { RESOURCES, ResourceError } from './resources';
...@@ -27,4 +27,5 @@ export type ResourcePayload<Q extends keyof typeof RESOURCES> = ...@@ -27,4 +27,5 @@ export type ResourcePayload<Q extends keyof typeof RESOURCES> =
Q extends 'user_info' ? UserInfo : Q extends 'user_info' ? UserInfo :
Q extends 'csrf' ? CsrfData : Q extends 'csrf' ? CsrfData :
Q extends 'custom_abi' ? CustomAbis : Q extends 'custom_abi' ? CustomAbis :
never; Q extends 'public_tags' ? PublicTags :
never;
...@@ -13,7 +13,7 @@ import { useForm, Controller } from 'react-hook-form'; ...@@ -13,7 +13,7 @@ import { useForm, Controller } from 'react-hook-form';
import type { CustomAbi, CustomAbis, CustomAbiErrors } from 'types/api/account'; import type { CustomAbi, CustomAbis, CustomAbiErrors } from 'types/api/account';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceErrorAccount } from 'lib/api/resources';
import { resourceKey } from 'lib/api/resources'; import { resourceKey } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
...@@ -84,7 +84,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -84,7 +84,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
onClose(); onClose();
}, },
onError: (error: ResourceError<{ errors: CustomAbiErrors}>) => { onError: (error: ResourceErrorAccount<CustomAbiErrors>) => {
const errorMap = error.payload?.errors; const errorMap = error.payload?.errors;
if (errorMap?.address_hash || errorMap?.name || errorMap?.abi) { if (errorMap?.address_hash || errorMap?.name || errorMap?.abi) {
errorMap?.address_hash && setError('contract_address_hash', { type: 'custom', message: getErrorMessage(errorMap, 'address_hash') }); errorMap?.address_hash && setError('contract_address_hash', { type: 'custom', message: getErrorMessage(errorMap, 'address_hash') });
......
...@@ -4,9 +4,9 @@ import React, { useCallback, useState } from 'react'; ...@@ -4,9 +4,9 @@ import React, { useCallback, useState } from 'react';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import type { PublicTags, PublicTag } from 'types/api/account'; import type { PublicTags, PublicTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import { resourceKey } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
type Props = { type Props = {
...@@ -23,17 +23,20 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete ...@@ -23,17 +23,20 @@ const DeletePublicTagModal: React.FC<Props> = ({ isOpen, onClose, data, onDelete
const tags = data.tags.split(';'); const tags = data.tags.split(';');
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const fetch = useFetch(); const apiFetch = useApiFetch();
const formBackgroundColor = useColorModeValue('white', 'gray.900'); const formBackgroundColor = useColorModeValue('white', 'gray.900');
const deleteApiKey = useCallback(() => { const deleteApiKey = useCallback(() => {
const body = { remove_reason: reason }; const body = { remove_reason: reason };
return fetch(`/node-api/account/public-tags/${ data.id }`, { method: 'DELETE', body }); return apiFetch('public_tags', {
}, [ data.id, fetch, reason ]); pathParams: { id: String(data.id) },
fetchParams: { method: 'DELETE', body },
});
}, [ data.id, apiFetch, reason ]);
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
onDeleteSuccess(); onDeleteSuccess();
queryClient.setQueryData([ QueryKeys.publicTags ], (prevData: PublicTags | undefined) => { queryClient.setQueryData([ resourceKey('public_tags') ], (prevData: PublicTags | undefined) => {
return prevData?.filter((item) => item.id !== data.id); return prevData?.filter((item) => item.id !== data.id);
}); });
}, [ queryClient, data, onDeleteSuccess ]); }, [ queryClient, data, onDeleteSuccess ]);
......
import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react'; import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { PublicTags, PublicTag } from 'types/api/account'; import type { PublicTag } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import useFetch from 'lib/hooks/useFetch'; import useApiQuery from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import PublicTagListItem from 'ui/publicTags/PublicTagTable/PublicTagListItem'; import PublicTagListItem from 'ui/publicTags/PublicTagTable/PublicTagListItem';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
...@@ -25,10 +23,8 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => { ...@@ -25,10 +23,8 @@ const PublicTagsData = ({ changeToFormScreen, onTagDelete }: Props) => {
const deleteModalProps = useDisclosure(); const deleteModalProps = useDisclosure();
const [ deleteModalData, setDeleteModalData ] = useState<PublicTag>(); const [ deleteModalData, setDeleteModalData ] = useState<PublicTag>();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, PublicTags>([ QueryKeys.publicTags ], async() => const { data, isLoading, isError } = useApiQuery('public_tags');
await fetch('/node-api/account/public-tags'));
const onDeleteModalClose = useCallback(() => { const onDeleteModalClose = useCallback(() => {
setDeleteModalData(undefined); setDeleteModalData(undefined);
......
...@@ -13,11 +13,11 @@ import type { FieldError, Path, SubmitHandler } from 'react-hook-form'; ...@@ -13,11 +13,11 @@ import type { FieldError, Path, SubmitHandler } from 'react-hook-form';
import { useForm, useFieldArray } from 'react-hook-form'; import { useForm, useFieldArray } from 'react-hook-form';
import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types/api/account'; import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types/api/account';
import { QueryKeys } from 'types/client/accountQueries';
import type { ResourceErrorAccount } from 'lib/api/resources';
import { resourceKey } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch';
import { EMAIL_REGEXP } from 'lib/validations/email'; import { EMAIL_REGEXP } from 'lib/validations/email';
import FormSubmitAlert from 'ui/shared/FormSubmitAlert'; import FormSubmitAlert from 'ui/shared/FormSubmitAlert';
...@@ -58,7 +58,7 @@ const ADDRESS_INPUT_BUTTONS_WIDTH = 100; ...@@ -58,7 +58,7 @@ const ADDRESS_INPUT_BUTTONS_WIDTH = 100;
const PublicTagsForm = ({ changeToDataScreen, data }: Props) => { const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const fetch = useFetch(); const apiFetch = useApiFetch();
const inputSize = { base: 'md', lg: 'lg' }; const inputSize = { base: 'md', lg: 'lg' };
const { control, handleSubmit, formState: { errors, isValid, isDirty }, setError } = useForm<Inputs>({ const { control, handleSubmit, formState: { errors, isValid, isDirty }, setError } = useForm<Inputs>({
...@@ -100,17 +100,20 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => { ...@@ -100,17 +100,20 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
}; };
if (!data?.id) { if (!data?.id) {
return fetch<PublicTag, PublicTagErrors>('/node-api/account/public-tags', { method: 'POST', body }); return apiFetch('public_tags', { fetchParams: { method: 'POST', body } });
} }
return fetch<PublicTag, PublicTagErrors>(`/node-api/account/public-tags/${ data.id }`, { method: 'PUT', body }); return apiFetch('public_tags', {
pathParams: { id: String(data.id) },
fetchParams: { method: 'PUT', body },
});
}; };
const mutation = useMutation(updatePublicTag, { const mutation = useMutation(updatePublicTag, {
onSuccess: async(data) => { onSuccess: async(data) => {
const response = data as unknown as PublicTag; const response = data as unknown as PublicTag;
queryClient.setQueryData([ QueryKeys.publicTags ], (prevData: PublicTags | undefined) => { queryClient.setQueryData([ resourceKey('public_tags') ], (prevData: PublicTags | undefined) => {
const isExisting = prevData && prevData.some((item) => item.id === response.id); const isExisting = prevData && prevData.some((item) => item.id === response.id);
if (isExisting) { if (isExisting) {
...@@ -128,13 +131,14 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => { ...@@ -128,13 +131,14 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
changeToDataScreen(true); changeToDataScreen(true);
}, },
onError: (e: ErrorType<PublicTagErrors>) => { onError: (error: ResourceErrorAccount<PublicTagErrors>) => {
if (e.error?.full_name || e.error?.email || e.error?.tags || e.error?.addresses || e.error?.additional_comment) { const errorMap = error.payload?.errors;
e.error?.full_name && setError('fullName', { type: 'custom', message: getErrorMessage(e.error, 'full_name') }); if (errorMap?.full_name || errorMap?.email || errorMap?.tags || errorMap?.addresses || errorMap?.additional_comment) {
e.error?.email && setError('email', { type: 'custom', message: getErrorMessage(e.error, 'email') }); errorMap?.full_name && setError('fullName', { type: 'custom', message: getErrorMessage(errorMap, 'full_name') });
e.error?.tags && setError('tags', { type: 'custom', message: getErrorMessage(e.error, 'tags') }); errorMap?.email && setError('email', { type: 'custom', message: getErrorMessage(errorMap, 'email') });
e.error?.addresses && setError('addresses.0.address', { type: 'custom', message: getErrorMessage(e.error, 'addresses') }); errorMap?.tags && setError('tags', { type: 'custom', message: getErrorMessage(errorMap, 'tags') });
e.error?.additional_comment && setError('comment', { type: 'custom', message: getErrorMessage(e.error, 'additional_comment') }); errorMap?.addresses && setError('addresses.0.address', { type: 'custom', message: getErrorMessage(errorMap, 'addresses') });
errorMap?.additional_comment && setError('comment', { type: 'custom', message: getErrorMessage(errorMap, 'additional_comment') });
} else { } else {
setAlertVisible(true); setAlertVisible(true);
} }
......
...@@ -12,7 +12,7 @@ import { useForm, Controller } from 'react-hook-form'; ...@@ -12,7 +12,7 @@ import { useForm, Controller } from 'react-hook-form';
import type { WatchlistErrors } from 'types/api/account'; import type { WatchlistErrors } from 'types/api/account';
import type { TWatchlistItem } from 'types/client/account'; import type { TWatchlistItem } from 'types/client/account';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceErrorAccount } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import { ADDRESS_REGEXP } from 'lib/validations/address'; import { ADDRESS_REGEXP } from 'lib/validations/address';
...@@ -112,7 +112,7 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd ...@@ -112,7 +112,7 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
await onSuccess(); await onSuccess();
setPending(false); setPending(false);
}, },
onError: (error: ResourceError<{errors: WatchlistErrors}>) => { onError: (error: ResourceErrorAccount<WatchlistErrors>) => {
setPending(false); setPending(false);
const errorMap = error.payload?.errors; const errorMap = error.payload?.errors;
if (errorMap?.address_hash || errorMap?.name) { if (errorMap?.address_hash || errorMap?.name) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment