mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-01-13 08:37:53 -05:00
132 lines
3.8 KiB
TypeScript
132 lines
3.8 KiB
TypeScript
import { useToast } from '@metafam/ds';
|
|
import {
|
|
ComposeDBImageMetadata,
|
|
composeDBProfileFieldAvatar,
|
|
getMimeType,
|
|
Maybe,
|
|
} from '@metafam/utils';
|
|
import { ReactElement, useCallback, useEffect, useState } from 'react';
|
|
|
|
import { useSetupFlow } from '#contexts/SetupContext';
|
|
import { useInsertCacheInvalidationMutation } from '#graphql/autogen/hasura-sdk';
|
|
import { CeramicError } from '#lib/errors';
|
|
import { errorHandler } from '#utils/errorHandler';
|
|
import { getImageDimensions } from '#utils/imageHelpers';
|
|
|
|
import { FileReaderData } from '../useImageReader';
|
|
import { useUser } from '../useUser';
|
|
import { useWeb3 } from '../useWeb3';
|
|
import { useSaveToComposeDB } from './useSaveToComposeDB';
|
|
|
|
export type PlayerSetupSaveToComposeDBProps = {
|
|
isChanged: boolean;
|
|
onComplete?: (nodeId?: string) => void;
|
|
pickedFile?: FileReaderData;
|
|
};
|
|
|
|
export function usePlayerSetupSaveToComposeDB({
|
|
isChanged,
|
|
onComplete = undefined,
|
|
pickedFile: fileData,
|
|
}: PlayerSetupSaveToComposeDBProps) {
|
|
const toast = useToast();
|
|
const { user } = useUser();
|
|
const { onNextPress } = useSetupFlow();
|
|
const [status, setStatus] = useState<Maybe<string | ReactElement>>();
|
|
const { w3storage } = useWeb3();
|
|
const { save: saveToComposeDB, status: saveStatus } = useSaveToComposeDB();
|
|
const [, invalidateCache] = useInsertCacheInvalidationMutation();
|
|
|
|
useEffect(() => {
|
|
if (saveStatus === 'authenticating') {
|
|
setStatus('Authenticating DID…');
|
|
}
|
|
}, [saveStatus]);
|
|
|
|
const onSubmit = useCallback(
|
|
async (values: Record<string, unknown>) => {
|
|
try {
|
|
let nodeId;
|
|
|
|
if (!isChanged) {
|
|
setStatus('No Change. Skipping Save…');
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, 10);
|
|
});
|
|
} else {
|
|
const payload = { ...values };
|
|
if (fileData?.file != null) {
|
|
// We have a file, thus this must be the avatar image. Here, we just
|
|
// compute a whole new ComposeDBImageMetadata object and don't use any information
|
|
// from the form
|
|
setStatus('Uploading images to web3.storage…');
|
|
|
|
const { file, dataURL } = fileData;
|
|
|
|
const ipfsHash = await w3storage?.uploadFile(file);
|
|
|
|
setStatus('Calculating image metadata…');
|
|
|
|
const imageMetadata = {
|
|
url: `ipfs://${ipfsHash}`,
|
|
mimeType: getMimeType(dataURL),
|
|
} as ComposeDBImageMetadata;
|
|
|
|
const { width, height } = await getImageDimensions(dataURL);
|
|
if (width && height) {
|
|
imageMetadata.width = width;
|
|
imageMetadata.height = height;
|
|
}
|
|
// composeDB doesn't like nulls
|
|
const cleanImageMetadata = Object.fromEntries(
|
|
Object.entries(imageMetadata).filter(([, v]) => v != null),
|
|
);
|
|
payload[composeDBProfileFieldAvatar] = cleanImageMetadata;
|
|
}
|
|
|
|
setStatus('Saving to ComposeDB…');
|
|
nodeId = await saveToComposeDB(payload);
|
|
|
|
if (user) {
|
|
setStatus('Invalidating Cache…');
|
|
await invalidateCache({ playerId: user.id });
|
|
}
|
|
}
|
|
|
|
if (onComplete) {
|
|
onComplete(nodeId);
|
|
} else {
|
|
onNextPress();
|
|
}
|
|
} catch (err) {
|
|
const heading = err instanceof CeramicError ? 'Ceramic Error' : 'Error';
|
|
toast({
|
|
title: heading,
|
|
description: (err as Error).message,
|
|
status: 'error',
|
|
isClosable: true,
|
|
duration: 12000,
|
|
});
|
|
errorHandler(err as Error);
|
|
setStatus(null);
|
|
}
|
|
},
|
|
[
|
|
fileData,
|
|
invalidateCache,
|
|
isChanged,
|
|
onComplete,
|
|
onNextPress,
|
|
saveToComposeDB,
|
|
toast,
|
|
user,
|
|
w3storage,
|
|
],
|
|
);
|
|
|
|
return {
|
|
onSubmit,
|
|
status,
|
|
};
|
|
}
|