feat: persisting profile layout changes in hasura

This commit is contained in:
dan13ram
2022-01-07 23:45:46 +05:30
committed by dan13ram
parent da68a8b145
commit 19f3b7fac2
4 changed files with 110 additions and 54 deletions

View File

@@ -33,7 +33,7 @@ export const PlayerAchievements: React.FC<Props> = ({
boxType={BoxType.PLAYER_ACHIEVEMENTS}
>
{(fakeData || []).slice(0, show ? 999 : 3).map((title) => (
<HStack alignItems="baseline" mb={3}>
<HStack alignItems="baseline" mb={3} key={title}>
<FaMedal color="#FBB112" />
<Text fontSize="md">{title}</Text>
</HStack>

View File

@@ -10,6 +10,7 @@ export const PlayerFragment = gql`
ethereum_address
pronouns
profile_layout @skip(if: $forLoginDisplay)
availability_hours @skip(if: $forLoginDisplay)
timezone @skip(if: $forLoginDisplay)
color_aspect @skip(if: $forLoginDisplay) {

View File

@@ -50,6 +50,16 @@ gql`
affected_rows
}
}
mutation UpdatePlayerProfileLayout($playerId: uuid!, $layout: String!) {
update_player_by_pk(
pk_columns: { id: $playerId }
_set: { profile_layout: $layout }
) {
id
profile_layout
}
}
`;
export const UpdateProfilePronouns = gql`

View File

@@ -9,6 +9,7 @@ import {
Flex,
MetaButton,
ResponsiveText,
useToast,
} from '@metafam/ds';
import { PageContainer } from 'components/Container';
import {
@@ -23,7 +24,10 @@ import {
import { PlayerAddSection } from 'components/Player/Section/PlayerAddSection';
import { PlayerSection } from 'components/Profile/PlayerSection';
import { HeadComponent } from 'components/Seo';
import { useInsertCacheInvalidationMutation } from 'graphql/autogen/types';
import {
useInsertCacheInvalidationMutation,
useUpdatePlayerProfileLayoutMutation,
} from 'graphql/autogen/types';
import { getPlayer } from 'graphql/getPlayer';
import { getTopPlayerUsernames } from 'graphql/getPlayers';
import { useUser, useWeb3 } from 'lib/hooks';
@@ -161,11 +165,24 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
}
}, [player, invalidateCache]);
// TODO: persist in hasura
const [savedLayoutData, setSavedLayoutData] = useState<ProfileLayoutData>({
layouts: DEFAULT_PLAYER_LAYOUTS,
layoutItems: DEFAULT_LAYOUT_ITEMS,
});
const toast = useToast();
const [
{ fetching: fetchingSaveRes },
saveLayoutData,
] = useUpdatePlayerProfileLayoutMutation();
const [saving, setSaving] = useState(false);
const layoutsFromDB = player.profile_layout
? JSON.parse(player.profile_layout)
: null;
const [savedLayoutData, setSavedLayoutData] = useState<ProfileLayoutData>(
layoutsFromDB || {
layouts: DEFAULT_PLAYER_LAYOUTS,
layoutItems: DEFAULT_LAYOUT_ITEMS,
},
);
const [
{ layoutItems: currentLayoutItems, layouts: currentLayouts },
@@ -176,53 +193,6 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
const [editable, setEditable] = useState(false);
const toggleEditLayout = useCallback(() => {
if (editable) {
const layoutData = {
layouts: removeBoxFromLayouts(
getBoxKey(BoxType.PLAYER_ADD_BOX, {}),
currentLayouts,
),
layoutItems: currentLayoutItems.filter(
(item) => item.boxType !== BoxType.PLAYER_ADD_BOX,
),
};
setCurrentLayoutData(layoutData);
setSavedLayoutData(layoutData);
} else {
const layoutData = {
layouts: addBoxToLayouts(BoxType.PLAYER_ADD_BOX, {}, currentLayouts),
layoutItems: [
...currentLayoutItems,
{
boxType: BoxType.PLAYER_ADD_BOX,
boxMetadata: {},
boxKey: getBoxKey(BoxType.PLAYER_ADD_BOX, {}),
},
],
};
setCurrentLayoutData(layoutData);
}
setEditable(!editable);
setChanged(false);
}, [editable, currentLayouts, currentLayoutItems]);
const toggleScrollLock = () => {
if (typeof window !== 'undefined') {
const body = document.querySelector('body');
if (body) body.classList.toggle('dashboard-edit');
}
return null;
};
const handleLayoutChange = useCallback(
(_layoutItems: Layout[], layouts: Layouts) => {
setCurrentLayoutData({ layouts, layoutItems: currentLayoutItems });
setChanged(true);
},
[currentLayoutItems],
);
const handleReset = useCallback(() => {
const layoutData = {
layouts: addBoxToLayouts(
@@ -246,6 +216,80 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
}, 300);
}, [savedLayoutData]);
const persistLayoutData = useCallback(
async (layoutData: ProfileLayoutData) => {
if (!user) return;
setSaving(true);
const { error } = await saveLayoutData({
playerId: user.id,
layout: JSON.stringify(layoutData),
});
if (error) {
const errorDetail = 'The octo is sad 😢';
toast({
title: 'Error',
description: `Unable to save layout. ${errorDetail}`,
status: 'error',
isClosable: true,
});
handleReset();
} else {
setCurrentLayoutData(layoutData);
setSavedLayoutData(layoutData);
}
setSaving(false);
},
[handleReset, saveLayoutData, toast, user],
);
const toggleEditLayout = useCallback(() => {
if (editable) {
const layoutData = {
layouts: removeBoxFromLayouts(
getBoxKey(BoxType.PLAYER_ADD_BOX, {}),
currentLayouts,
),
layoutItems: currentLayoutItems.filter(
(item) => item.boxType !== BoxType.PLAYER_ADD_BOX,
),
};
persistLayoutData(layoutData);
} else {
const layoutData = {
layouts: addBoxToLayouts(BoxType.PLAYER_ADD_BOX, {}, currentLayouts),
layoutItems: [
...currentLayoutItems,
{
boxType: BoxType.PLAYER_ADD_BOX,
boxMetadata: {},
boxKey: getBoxKey(BoxType.PLAYER_ADD_BOX, {}),
},
],
};
setCurrentLayoutData(layoutData);
}
setEditable(!editable);
setChanged(false);
}, [editable, currentLayouts, currentLayoutItems, persistLayoutData]);
const toggleScrollLock = () => {
if (typeof window !== 'undefined') {
const body = document.querySelector('body');
if (body) body.classList.toggle('dashboard-edit');
}
return null;
};
const handleLayoutChange = useCallback(
(_layoutItems: Layout[], layouts: Layouts) => {
setCurrentLayoutData({ layouts, layoutItems: currentLayoutItems });
setChanged(true);
},
[currentLayoutItems],
);
const wrapperSX = useMemo(() => gridConfig.wrapper(editable), [editable]);
const displayLayouts = useMemo(() => makeLayouts(editable, currentLayouts), [
@@ -345,6 +389,7 @@ export const Grid: React.FC<Props> = ({ player }): ReactElement => {
color={editable ? 'red.400' : 'pinkShadeOne'}
leftIcon={<EditIcon />}
transition="color 0.2s ease"
isLoading={saving || fetchingSaveRes}
onClick={toggleEditLayout}
>
<ResponsiveText