Fixed edit profile field saving, updated useUser to load from composeDB

This commit is contained in:
Alec LaLonde
2023-02-24 21:13:17 -07:00
committed by Alec LaLonde
parent 509a45cd5c
commit 907cdf17ca
15 changed files with 91 additions and 117 deletions

View File

@@ -30,16 +30,17 @@ import {
} from '@metafam/ds';
import {
ComposeDBImageMetadata,
ComposeDBProfile,
getMimeType,
HasuraImageFieldKey,
hasuraImageFields,
isHasuraImageField,
profileMapping,
} from '@metafam/utils';
import { Maybe, Player } from 'graphql/autogen/types';
import { Maybe, Player, Profile } from 'graphql/autogen/types';
import { getPlayer } from 'graphql/getPlayer';
import { PlayerProfile } from 'graphql/types';
import { useWeb3 } from 'lib/hooks';
import { hasuraToComposeDBProfile } from 'lib/hooks/ceramic/usePlayerSetupSaveToComposeDB';
import { useSaveToComposeDB } from 'lib/hooks/ceramic/useSaveToComposeDB';
import React, {
createRef,
@@ -174,7 +175,10 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
),
);
const profile: ComposeDBProfile = { ...changedInputs };
const profile: PlayerProfile = { ...changedInputs };
const profileImages = Object.fromEntries(
hasuraImageFields.map((field) => [field, null]),
) as Record<HasuraImageFieldKey, Maybe<ComposeDBImageMetadata>>;
const toType = (key: string) => {
const match = key.match(/^(.+?)(Image)?(URL)$/i);
@@ -219,8 +223,7 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
imageMetadata.height = height;
}
const composeDBKey = profileMapping[key as HasuraImageFieldKey];
profile[composeDBKey] = imageMetadata;
profileImages[key as HasuraImageFieldKey] = imageMetadata;
}
}),
);
@@ -228,7 +231,8 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
setStatus('Saving to Ceramic…');
const ceramicStreamID = await save(profile);
const payload = hasuraToComposeDBProfile(profile, profileImages);
const ceramicStreamID = await save(payload);
// if they changed their username, the page will 404 on reload
if (player && inputs.username !== username) {

View File

@@ -4,24 +4,10 @@ import { FlexContainer } from 'components/Container';
import { MetaLink } from 'components/Link';
import { PlayerTile } from 'components/Player/PlayerTile';
import { useUser, useWeb3 } from 'lib/hooks';
import {
hydratePlayerProfile,
useGetPlayerProfileFromComposeDB,
} from 'lib/hooks/ceramic/useGetPlayerProfileFromComposeDB';
import React, { useEffect, useState } from 'react';
export const SetupDone: React.FC = () => {
const { user } = useUser();
const { connected } = useWeb3();
const { result } = useGetPlayerProfileFromComposeDB(user?.ceramicProfileId);
const [hydratedPlayer, setHydratedPlayer] = useState(user);
useEffect(() => {
if (user && result) {
setHydratedPlayer(hydratePlayerProfile(user, result));
}
}, [result, user]);
if (!user || !connected) {
return (
@@ -41,7 +27,7 @@ export const SetupDone: React.FC = () => {
justify="center"
align="center"
>
{hydratedPlayer && <PlayerTile player={hydratedPlayer} />}
<PlayerTile player={user} />
<Stack spacing={4} p={4} maxW="25rem" fontSize="md" h="100%">
<Text fontSize="lg">Congrats on making yourself a profile! 🎉</Text>
<Text fontSize="md">

View File

@@ -5,14 +5,8 @@ import { composeDBDefinition, Maybe } from '@metafam/utils';
import { CONFIG } from 'config';
import { DIDSession } from 'did-session';
import { cacheDIDSession, getCachedDIDSession } from 'lib/auth';
import { useWeb3 } from 'lib/hooks';
import {
createContext,
PropsWithChildren,
useCallback,
useContext,
useState,
} from 'react';
import { useWeb3 } from 'lib/hooks/useWeb3';
import { createContext, PropsWithChildren, useCallback, useState } from 'react';
import { errorHandler } from 'utils/errorHandler';
export type ComposeDBContextType = {
@@ -109,6 +103,3 @@ export const ComposeDBContextProvider: React.FC<PropsWithChildren> = ({
</ComposeDBContext.Provider>
);
};
export const useComposeDB = (): ComposeDBContextType =>
useContext(ComposeDBContext);

View File

@@ -2,6 +2,7 @@ import { Player } from 'graphql/autogen/types';
import { buildPlayerProfileQuery } from 'graphql/composeDB/queries/profile';
import { getPlayer } from 'graphql/getPlayer';
import { ComposeDBProfileQueryResult } from 'graphql/types';
import { useComposeDB } from 'lib/hooks/ceramic/useComposeDB';
import { hydratePlayerProfile } from 'lib/hooks/ceramic/useGetPlayerProfileFromComposeDB';
import {
createContext,
@@ -12,8 +13,6 @@ import {
useState,
} from 'react';
import { useComposeDB } from './ComposeDBContext';
export type PlayerHydrationContextType = {
hydratedPlayer: Player;
isHydrating: boolean;

View File

@@ -9,8 +9,6 @@ import React, {
} from 'react';
import { SetupOptions } from 'utils/setupOptions';
import { ComposeDBContextProvider } from './ComposeDBContext';
const urlPrefix = '/profile/setup/';
type SetupContextType = {
@@ -71,19 +69,17 @@ export const SetupContextProvider: React.FC<PropsWithChildren> = ({
}, [router, options, stepIndex]);
return (
<ComposeDBContextProvider>
<SetupContext.Provider
value={{
options,
stepIndex,
onNextPress,
onBackPress,
nextButtonLabel,
}}
>
{children}
</SetupContext.Provider>
</ComposeDBContextProvider>
<SetupContext.Provider
value={{
options,
stepIndex,
onNextPress,
onBackPress,
nextButtonLabel,
}}
>
{children}
</SetupContext.Provider>
);
};

View File

@@ -64,6 +64,8 @@ export type GuildMetadata = {
};
};
export type PlayerProfile = Omit<Profile, 'playerId' | 'player' | 'id'>;
export type ComposeDBProfileQueryResult = {
node: ComposeDBProfile;
};

View File

@@ -0,0 +1,8 @@
import {
ComposeDBContext,
ComposeDBContextType,
} from 'contexts/ComposeDBContext';
import { useContext } from 'react';
export const useComposeDB = (): ComposeDBContextType =>
useContext(ComposeDBContext);

View File

@@ -8,7 +8,6 @@ import {
Maybe,
profileMapping,
} from '@metafam/utils';
import { useComposeDB } from 'contexts/ComposeDBContext';
import { Player } from 'graphql/autogen/types';
import { buildPlayerProfileQuery } from 'graphql/composeDB/queries/profile';
import { ComposeDBProfileQueryResult } from 'graphql/types';
@@ -16,6 +15,8 @@ import { CeramicError } from 'lib/errors';
import { useEffect, useState } from 'react';
import { errorHandler } from 'utils/errorHandler';
import { useComposeDB } from './useComposeDB';
const genericFetchError = new CeramicError(
'An unexpected error occurred when querying Ceramic.',
);
@@ -65,7 +66,7 @@ export const useGetPlayerProfileFromComposeDB = (
export const hydratePlayerProfile = (
player: Player,
profileData: ComposeDBProfile,
) => {
): Player => {
const hasComposeDBData = Object.values(profileData).some((value) => !!value);
if (hasComposeDBData) {
const hasuraProfile = composeDBToHasuraProfile(profileData);

View File

@@ -2,19 +2,17 @@ import { useToast } from '@metafam/ds';
import {
ComposeDBField,
ComposeDBImageMetadata,
ComposeDBPayloadValue,
composeDBProfileFieldAvatar,
composeDBProfileFieldFiveColorDisposition,
dispositionFor,
getMimeType,
HasuraImageFieldKey,
isComposeDBImageField,
isImageMetadata,
Maybe,
profileMapping,
} from '@metafam/utils';
import { useSetupFlow } from 'contexts/SetupContext';
import { Profile } from 'graphql/autogen/types';
import { PlayerProfile } from 'graphql/types';
import { CeramicError } from 'lib/errors';
import { ReactElement, useCallback, useEffect, useState } from 'react';
import { errorHandler } from 'utils/errorHandler';
@@ -128,7 +126,7 @@ export function usePlayerSetupSaveToComposeDB({
}
export const hasuraToComposeDBProfile = (
profile: Profile,
profile: PlayerProfile,
images: Record<HasuraImageFieldKey, Maybe<ComposeDBImageMetadata>>,
) => {
// todo we should be able to make this typesafe

View File

@@ -1,5 +1,4 @@
import { ComposeDBProfile, Maybe } from '@metafam/utils';
import { useComposeDB } from 'contexts/ComposeDBContext';
import { useLinkOwnCeramicNodeMutation } from 'graphql/autogen/types';
import {
ComposeDBCreateProfileResponseData,
@@ -9,6 +8,7 @@ import { CeramicError, handleCeramicAuthenticationError } from 'lib/errors';
import { useCallback, useState } from 'react';
import { useUser } from '../useUser';
import { useComposeDB } from './useComposeDB';
export type SaveToComposeDBStatus = 'authenticating' | 'querying' | undefined;

View File

@@ -2,9 +2,14 @@ import { Maybe } from '@metafam/utils';
import { Player, useGetMeQuery } from 'graphql/autogen/types';
import { useWeb3 } from 'lib/hooks/useWeb3';
import { useRouter } from 'next/router';
import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { CombinedError, RequestPolicy } from 'urql';
import {
hydratePlayerProfile,
useGetPlayerProfileFromComposeDB,
} from './ceramic/useGetPlayerProfileFromComposeDB';
type UseUserOpts = {
redirectTo?: string;
redirectIfNotFound?: boolean;
@@ -30,7 +35,9 @@ export const useUser = ({
});
const [me] = data?.me ?? [];
const user = useMemo(
const [hydratedPlayer, setHydratedPlayer] = useState<Player | null>(null);
const hasuraUser = useMemo(
() =>
!error && !fetching && authToken && me && connected
? (me.record as Player)
@@ -38,6 +45,22 @@ export const useUser = ({
[error, authToken, me, connected, fetching],
);
const {
result,
fetching: composeDBFetching,
error: composeDBError,
} = useGetPlayerProfileFromComposeDB(hasuraUser?.ceramicProfileId);
useEffect(() => {
if (hasuraUser) {
if (hasuraUser.ceramicProfileId == null || composeDBError) {
setHydratedPlayer(hasuraUser);
} else if (hasuraUser && result) {
setHydratedPlayer(hydratePlayerProfile(hasuraUser, result));
}
}
}, [result, hasuraUser, composeDBError]);
if (error) {
console.error('useUser error', error);
}
@@ -52,16 +75,23 @@ export const useUser = ({
// If redirectTo is set and redirectIfNotFound is set then
// redirect if the user was not found.
if (redirectTo && redirectIfNotFound && !user) {
if (redirectTo && redirectIfNotFound && !hasuraUser) {
router.push(redirectTo);
}
}, [router, user, fetching, connecting, redirectIfNotFound, redirectTo]);
}, [
router,
hasuraUser,
fetching,
connecting,
redirectIfNotFound,
redirectTo,
]);
return {
connecting,
connected,
user,
fetching,
user: hydratedPlayer,
fetching: fetching || composeDBFetching,
error,
};
};

View File

@@ -6,6 +6,7 @@ import { ChakraProvider, CSSReset, MetaTheme } from '@metafam/ds';
import { UserbackProvider } from '@userback/react';
import { MegaMenu } from 'components/MegaMenu/index';
import { CONFIG } from 'config';
import { ComposeDBContextProvider } from 'contexts/ComposeDBContext';
import { Web3ContextProvider } from 'contexts/Web3Context';
import { wrapUrqlClient } from 'graphql/client';
import Head from 'next/head';
@@ -59,9 +60,11 @@ const App: React.FC<WithUrqlProps> = ({
{environment === 'production' && <Analytics />}
</Head>
<Web3ContextProvider {...{ resetUrqlClient }}>
<MegaMenu hide={pageProps.hideTopMenu}>
<Component {...pageProps} />
</MegaMenu>
<ComposeDBContextProvider>
<MegaMenu hide={pageProps.hideTopMenu}>
<Component {...pageProps} />
</MegaMenu>
</ComposeDBContextProvider>
</Web3ContextProvider>
</ChakraProvider>
</React.StrictMode>

View File

@@ -11,7 +11,6 @@ import {
} from 'components/Player/Section/config';
import { HeadComponent } from 'components/Seo';
import { CONFIG } from 'config';
import { ComposeDBContextProvider } from 'contexts/ComposeDBContext';
import {
PlayerHydrationContextProvider,
usePlayerHydrationContext,
@@ -60,14 +59,12 @@ export const PlayerPage: React.FC<PlayerPageProps> = ({
if (!player) return <Page404 />;
return (
<ComposeDBContextProvider>
<PlayerHydrationContextProvider
player={player}
isHydratedAlready={isHydratedFromComposeDB}
>
<PlayerPageContent />
</PlayerHydrationContextProvider>
</ComposeDBContextProvider>
<PlayerHydrationContextProvider
player={player}
isHydratedAlready={isHydratedFromComposeDB}
>
<PlayerPageContent />
</PlayerHydrationContextProvider>
);
};

View File

@@ -3010,7 +3010,8 @@ input jsonb_comparison_exp {
}
type LinkCeramicProfileNodeResponse {
verified: Boolean
error: String
verified: Boolean!
}
"""

View File

@@ -5751,11 +5751,6 @@
elliptic "^6.5.4"
typedarray-to-buffer "^4.0.0"
"@tokenizer/token@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
"@tootallnate/once@1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
@@ -11699,15 +11694,6 @@ file-selector@^0.6.0:
dependencies:
tslib "^2.4.0"
file-type@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-18.2.0.tgz#c2abec00d1af0f09151e1549e3588aab0bac5001"
integrity sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==
dependencies:
readable-web-to-node-stream "^3.0.2"
strtok3 "^7.0.0"
token-types "^5.0.1"
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@@ -17544,11 +17530,6 @@ pbkdf2@^3.0.17, pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
peek-readable@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==
peer-id@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/peer-id/-/peer-id-0.16.0.tgz#0913062cfa4378707fe69c949b5720b3efadbf32"
@@ -18640,13 +18621,6 @@ readable-stream@~1.0.15:
isarray "0.0.1"
string_decoder "~0.10.x"
readable-web-to-node-stream@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb"
integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==
dependencies:
readable-stream "^3.6.0"
readdir-scoped-modules@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309"
@@ -20105,14 +20079,6 @@ strong-log-transformer@^2.1.0:
minimist "^1.2.0"
through "^2.3.4"
strtok3@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5"
integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==
dependencies:
"@tokenizer/token" "^0.3.0"
peek-readable "^5.0.0"
style-to-js@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.1.tgz#417786986cda61d4525c80aed9d1123a6a7af9b8"
@@ -20471,14 +20437,6 @@ toidentifier@1.0.1:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
token-types@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4"
integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==
dependencies:
"@tokenizer/token" "^0.3.0"
ieee754 "^1.2.1"
touch@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"