can add own/wanted items from item page
the buttons work now! but only when adding 😅 remove comes next!
This commit is contained in:
parent
d2671d0fa6
commit
57889a3a88
3 changed files with 167 additions and 76 deletions
|
@ -25,7 +25,7 @@ GRANT INSERT, UPDATE ON swf_assets TO impress2020;
|
||||||
GRANT INSERT ON modeling_logs TO impress2020;
|
GRANT INSERT ON modeling_logs TO impress2020;
|
||||||
|
|
||||||
-- User data tables
|
-- User data tables
|
||||||
GRANT SELECT ON closet_hangers TO impress2020;
|
GRANT SELECT, INSERT ON closet_hangers TO impress2020;
|
||||||
GRANT SELECT ON closet_lists TO impress2020;
|
GRANT SELECT ON closet_lists TO impress2020;
|
||||||
GRANT SELECT ON item_outfit_relationships TO impress2020;
|
GRANT SELECT ON item_outfit_relationships TO impress2020;
|
||||||
GRANT SELECT ON outfits TO impress2020;
|
GRANT SELECT ON outfits TO impress2020;
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {
|
||||||
} from "@chakra-ui/icons";
|
} from "@chakra-ui/icons";
|
||||||
import { MdPause, MdPlayArrow } from "react-icons/md";
|
import { MdPause, MdPlayArrow } from "react-icons/md";
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
import { useQuery } from "@apollo/client";
|
import { useQuery, useMutation } from "@apollo/client";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -41,6 +41,7 @@ import {
|
||||||
} from "./components/useOutfitAppearance";
|
} from "./components/useOutfitAppearance";
|
||||||
import OutfitPreview from "./components/OutfitPreview";
|
import OutfitPreview from "./components/OutfitPreview";
|
||||||
import SpeciesColorPicker from "./components/SpeciesColorPicker";
|
import SpeciesColorPicker from "./components/SpeciesColorPicker";
|
||||||
|
import useCurrentUser from "./components/useCurrentUser";
|
||||||
import { useLocalStorage } from "./util";
|
import { useLocalStorage } from "./util";
|
||||||
import WIPCallout from "./components/WIPCallout";
|
import WIPCallout from "./components/WIPCallout";
|
||||||
|
|
||||||
|
@ -55,10 +56,12 @@ function ItemPage() {
|
||||||
* `isEmbedded` prop is true, so we know not to e.g. set the page title.
|
* `isEmbedded` prop is true, so we know not to e.g. set the page title.
|
||||||
*/
|
*/
|
||||||
export function ItemPageContent({ itemId, isEmbedded }) {
|
export function ItemPageContent({ itemId, isEmbedded }) {
|
||||||
|
const { isLoggedIn } = useCurrentUser();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing="8">
|
<VStack spacing="8">
|
||||||
<ItemPageHeader itemId={itemId} isEmbedded={isEmbedded} />
|
<ItemPageHeader itemId={itemId} isEmbedded={isEmbedded} />
|
||||||
<ItemPageOwnWantButtons itemId={itemId} />
|
{isLoggedIn && <ItemPageOwnWantButtons itemId={itemId} />}
|
||||||
{!isEmbedded && <ItemPageOutfitPreview itemId={itemId} />}
|
{!isEmbedded && <ItemPageOutfitPreview itemId={itemId} />}
|
||||||
<WIPCallout>Trade lists coming soon!</WIPCallout>
|
<WIPCallout>Trade lists coming soon!</WIPCallout>
|
||||||
</VStack>
|
</VStack>
|
||||||
|
@ -311,10 +314,9 @@ function ItemPageOwnWantButtons({ itemId }) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const [currentUserOwnsThis, setCurrentUserOwnsThis] = React.useState(false);
|
|
||||||
const [currentUserWantsThis, setCurrentUserWantsThis] = React.useState(false);
|
const [currentUserWantsThis, setCurrentUserWantsThis] = React.useState(false);
|
||||||
|
|
||||||
const { loading, error } = useQuery(
|
const { loading, error, data } = useQuery(
|
||||||
gql`
|
gql`
|
||||||
query ItemPageOwnWantButtons($itemId: ID!) {
|
query ItemPageOwnWantButtons($itemId: ID!) {
|
||||||
item(id: $itemId) {
|
item(id: $itemId) {
|
||||||
|
@ -327,7 +329,6 @@ function ItemPageOwnWantButtons({ itemId }) {
|
||||||
{
|
{
|
||||||
variables: { itemId },
|
variables: { itemId },
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
setCurrentUserOwnsThis(data?.item?.currentUserOwnsThis || false);
|
|
||||||
setCurrentUserWantsThis(data?.item?.currentUserWantsThis || false);
|
setCurrentUserWantsThis(data?.item?.currentUserWantsThis || false);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -340,82 +341,172 @@ function ItemPageOwnWantButtons({ itemId }) {
|
||||||
return (
|
return (
|
||||||
<Box display="flex">
|
<Box display="flex">
|
||||||
<SubtleSkeleton isLoaded={!loading} marginRight="4">
|
<SubtleSkeleton isLoaded={!loading} marginRight="4">
|
||||||
<Box as="label">
|
<ItemPageOwnButton
|
||||||
<VisuallyHidden
|
itemId={itemId}
|
||||||
as="input"
|
isChecked={data?.item?.currentUserOwnsThis}
|
||||||
type="checkbox"
|
/>
|
||||||
checked={currentUserOwnsThis}
|
|
||||||
onChange={(e) => {
|
|
||||||
setCurrentUserOwnsThis(e.target.checked);
|
|
||||||
toast({
|
|
||||||
title: "Todo: This doesn't actually work yet!",
|
|
||||||
status: "info",
|
|
||||||
duration: 1500,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
as="div"
|
|
||||||
colorScheme={currentUserOwnsThis ? "green" : "gray"}
|
|
||||||
size="lg"
|
|
||||||
cursor="pointer"
|
|
||||||
transitionDuration="0.4s"
|
|
||||||
className={css`
|
|
||||||
input:focus + & {
|
|
||||||
box-shadow: ${theme.shadows.outline};
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<IconCheckbox
|
|
||||||
icon={<CheckIcon />}
|
|
||||||
isChecked={currentUserOwnsThis}
|
|
||||||
marginRight="0.5em"
|
|
||||||
/>
|
|
||||||
I own this
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</SubtleSkeleton>
|
</SubtleSkeleton>
|
||||||
|
|
||||||
<SubtleSkeleton isLoaded={!loading}>
|
<SubtleSkeleton isLoaded={!loading}>
|
||||||
<Box as="label">
|
<ItemPageWantButton
|
||||||
<VisuallyHidden
|
itemId={itemId}
|
||||||
as="input"
|
isChecked={data?.item?.currentUserWantsThis}
|
||||||
type="checkbox"
|
/>
|
||||||
isChecked={currentUserWantsThis}
|
|
||||||
onChange={(e) => {
|
|
||||||
setCurrentUserWantsThis(e.target.checked);
|
|
||||||
toast({
|
|
||||||
title: "Todo: This doesn't actually work yet!",
|
|
||||||
status: "info",
|
|
||||||
duration: 1500,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
as="div"
|
|
||||||
colorScheme={currentUserWantsThis ? "blue" : "gray"}
|
|
||||||
size="lg"
|
|
||||||
cursor="pointer"
|
|
||||||
transitionDuration="0.4s"
|
|
||||||
className={css`
|
|
||||||
input:focus + & {
|
|
||||||
box-shadow: ${theme.shadows.outline};
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<IconCheckbox
|
|
||||||
icon={<StarIcon />}
|
|
||||||
isChecked={currentUserWantsThis}
|
|
||||||
marginRight="0.5em"
|
|
||||||
/>
|
|
||||||
I want this
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</SubtleSkeleton>
|
</SubtleSkeleton>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ItemPageOwnButton({ itemId, isChecked }) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const [sendAddMutation] = useMutation(
|
||||||
|
gql`
|
||||||
|
mutation ItemPageOwnButtonAdd($itemId: ID!) {
|
||||||
|
addToItemsCurrentUserOwns(itemId: $itemId) {
|
||||||
|
id
|
||||||
|
currentUserOwnsThis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
variables: { itemId },
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: "Mutation",
|
||||||
|
addToItemsCurrentUserOwns: {
|
||||||
|
__typename: "Item",
|
||||||
|
id: itemId,
|
||||||
|
currentUserOwnsThis: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box as="label">
|
||||||
|
<VisuallyHidden
|
||||||
|
as="input"
|
||||||
|
type="checkbox"
|
||||||
|
checked={isChecked}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.checked) {
|
||||||
|
sendAddMutation().catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
toast({
|
||||||
|
title: "We had trouble adding this to the items you own.",
|
||||||
|
description: "Check your internet connection, and try again.",
|
||||||
|
status: "error",
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "Todo: This doesn't actually work yet!",
|
||||||
|
status: "info",
|
||||||
|
duration: 1500,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
as="div"
|
||||||
|
colorScheme={isChecked ? "green" : "gray"}
|
||||||
|
size="lg"
|
||||||
|
cursor="pointer"
|
||||||
|
transitionDuration="0.4s"
|
||||||
|
className={css`
|
||||||
|
input:focus + & {
|
||||||
|
box-shadow: ${theme.shadows.outline};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<IconCheckbox
|
||||||
|
icon={<CheckIcon />}
|
||||||
|
isChecked={isChecked}
|
||||||
|
marginRight="0.5em"
|
||||||
|
/>
|
||||||
|
I own this
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemPageWantButton({ itemId, isChecked }) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
const [sendAddMutation] = useMutation(
|
||||||
|
gql`
|
||||||
|
mutation ItemPageWantButtonAdd($itemId: ID!) {
|
||||||
|
addToItemsCurrentUserWants(itemId: $itemId) {
|
||||||
|
id
|
||||||
|
currentUserWantsThis
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
variables: { itemId },
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: "Mutation",
|
||||||
|
addToItemsCurrentUserWants: {
|
||||||
|
__typename: "Item",
|
||||||
|
id: itemId,
|
||||||
|
currentUserWantsThis: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box as="label">
|
||||||
|
<VisuallyHidden
|
||||||
|
as="input"
|
||||||
|
type="checkbox"
|
||||||
|
isChecked={isChecked}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.checked) {
|
||||||
|
sendAddMutation().catch((e) => {
|
||||||
|
console.error(e);
|
||||||
|
toast({
|
||||||
|
title: "We had trouble adding this to the items you want.",
|
||||||
|
description: "Check your internet connection, and try again.",
|
||||||
|
status: "error",
|
||||||
|
duration: 5000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast({
|
||||||
|
title: "Todo: This doesn't actually work yet!",
|
||||||
|
status: "info",
|
||||||
|
duration: 1500,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
as="div"
|
||||||
|
colorScheme={isChecked ? "blue" : "gray"}
|
||||||
|
size="lg"
|
||||||
|
cursor="pointer"
|
||||||
|
transitionDuration="0.4s"
|
||||||
|
className={css`
|
||||||
|
input:focus + & {
|
||||||
|
box-shadow: ${theme.shadows.outline};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<IconCheckbox
|
||||||
|
icon={<StarIcon />}
|
||||||
|
isChecked={isChecked}
|
||||||
|
marginRight="0.5em"
|
||||||
|
/>
|
||||||
|
I want this
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function IconCheckbox({ icon, isChecked, ...props }) {
|
function IconCheckbox({ icon, isChecked, ...props }) {
|
||||||
return (
|
return (
|
||||||
<Box display="grid" gridTemplateAreas="the-same-area" {...props}>
|
<Box display="grid" gridTemplateAreas="the-same-area" {...props}>
|
||||||
|
|
|
@ -4,7 +4,7 @@ function useCurrentUser() {
|
||||||
const { isLoading, isAuthenticated, user } = useAuth0();
|
const { isLoading, isAuthenticated, user } = useAuth0();
|
||||||
|
|
||||||
if (isLoading || !isAuthenticated) {
|
if (isLoading || !isAuthenticated) {
|
||||||
return { id: null, username: null };
|
return { id: null, username: null, isLoggedIn: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Users created correctly should have these attributes... but I'm
|
// NOTE: Users created correctly should have these attributes... but I'm
|
||||||
|
@ -13,7 +13,7 @@ function useCurrentUser() {
|
||||||
const id = user.sub?.match(/^auth0\|impress-([0-9]+)$/)?.[1];
|
const id = user.sub?.match(/^auth0\|impress-([0-9]+)$/)?.[1];
|
||||||
const username = user["https://oauth.impress-2020.openneo.net/username"];
|
const username = user["https://oauth.impress-2020.openneo.net/username"];
|
||||||
|
|
||||||
return { id, username };
|
return { id, username, isLoggedIn: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useCurrentUser;
|
export default useCurrentUser;
|
||||||
|
|
Loading…
Reference in a new issue