Skip to content

Commit

Permalink
add support for updating mission data
Browse files Browse the repository at this point in the history
  • Loading branch information
datadanne committed Sep 27, 2023
1 parent 50af269 commit 01c0aae
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 36 deletions.
205 changes: 172 additions & 33 deletions garage/src/components/CreateMissionModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Result } from "@tableland/sdk";
import {
Button,
FormControl,
Expand All @@ -25,12 +26,13 @@ import {
useDisclosure,
useToast,
} from "@chakra-ui/react";
import isEqual from "lodash/isEqual";
import { DeleteIcon } from "@chakra-ui/icons";
import { ChainAwareButton } from "./ChainAwareButton";
import { Database } from "@tableland/sdk";
import { useSigner } from "../hooks/useSigner";
import { isPresent } from "../utils/types";
import { MissionReward, MissionDeliverable } from "../types";
import { Mission, MissionReward, MissionDeliverable } from "../types";
import { secondaryChain, deployment } from "../env";

const { missionsTable } = deployment;
Expand Down Expand Up @@ -176,16 +178,24 @@ const StateImportModal = ({
);
};

export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
const toast = useToast();
const signer = useSigner({ chainId: secondaryChain.id });

const db = useMemo(() => {
if (signer) return new Database({ signer });
}, [signer]);

const [formState, setFormState] = useState<FormState>(initialFormState);
type BaseModalProps = ModalProps & {
title: string;
isFormValid: boolean;
formState: FormState;
setFormState: React.Dispatch<React.SetStateAction<FormState>>;
onMutate?: (formState: FormState) => Promise<Result<never>>;
};

const BaseMissionModal = ({
isOpen,
onClose,
title,
formState,
setFormState,
isFormValid,
onMutate,
}: BaseModalProps) => {
const toast = useToast();
const {
name,
description,
Expand All @@ -198,34 +208,17 @@ export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
maxNumberOfContributions,
} = formState;

const isFormValid = useMemo(() => isValid(formState), [formState]);
const [txnState, setTxnState] = useState<
"idle" | "querying" | "success" | "fail"
>("idle");

const onSubmit = useCallback(async () => {
if (!db) return;
if (!onMutate) return;

setTxnState("querying");

try {
const { meta: insert } = await db
.prepare(
`INSERT INTO ${missionsTable} (name, description, tags, requirements, deliverables, rewards, contributions_start_block, contributions_end_block, max_number_of_contributions, contributions_disabled) VALUES (?, ?, JSON(?), JSON(?), JSON(?), JSON(?), ?, ?, ?, 0)`
)
.bind(
name,
description,
JSON.stringify(tags),
JSON.stringify(requirements),
JSON.stringify(deliverables),
JSON.stringify(rewards),
contributionsStartBlock,
contributionsEndBlock,
maxNumberOfContributions
)
.run();

const { meta: insert } = await onMutate(formState);
await insert.txn?.wait();
setTxnState("success");
toast({ title: "Success", status: "success", duration: 7_500 });
Expand All @@ -244,7 +237,7 @@ export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
}
}
}
}, [db, formState, setTxnState, toast]);
}, [onMutate, formState, setTxnState, toast]);

const onNameInputChanged = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
Expand Down Expand Up @@ -448,10 +441,9 @@ export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {

useEffect(() => {
if (isOpen) {
setFormState(initialFormState);
setTxnState("idle");
}
}, [isOpen, setFormState, setTxnState]);
}, [isOpen, setTxnState]);

const {
isOpen: exportIsOpen,
Expand Down Expand Up @@ -481,7 +473,7 @@ export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
<Modal isOpen={isOpen} onClose={onClose} size="xl">
<ModalOverlay />
<ModalContent>
<ModalHeader>Create Mission</ModalHeader>
<ModalHeader>{title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<FormControl>
Expand Down Expand Up @@ -758,3 +750,150 @@ export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
</>
);
};

export const CreateMissionModal = ({ isOpen, onClose }: ModalProps) => {
const signer = useSigner({ chainId: secondaryChain.id });

const db = useMemo(() => {
if (signer) return new Database({ signer });
}, [signer]);

const [formState, setFormState] = useState<FormState>(initialFormState);

const isFormValid = useMemo(() => isValid(formState), [formState]);

const mutate = db
? (state: FormState) => {
const {
name,
description,
tags,
requirements,
deliverables,
rewards,
contributionsStartBlock,
contributionsEndBlock,
maxNumberOfContributions,
} = state;

return db
.prepare(
`INSERT INTO ${missionsTable} (name, description, tags, requirements, deliverables, rewards, contributions_start_block, contributions_end_block, max_number_of_contributions, contributions_disabled) VALUES (?, ?, JSON(?), JSON(?), JSON(?), JSON(?), ?, ?, ?, 0)`
)
.bind(
name,
description,
JSON.stringify(tags),
JSON.stringify(requirements),
JSON.stringify(deliverables),
JSON.stringify(rewards),
contributionsStartBlock,
contributionsEndBlock,
maxNumberOfContributions
)
.run();
}
: undefined;

useEffect(() => {
if (isOpen) {
setFormState(initialFormState);
}
}, [isOpen, setFormState]);

return (
<BaseMissionModal
title="Create Mission"
formState={formState}
setFormState={setFormState}
isFormValid={isFormValid}
isOpen={isOpen}
onClose={onClose}
onMutate={mutate}
/>
);
};

type EditModalProps = { mission: Mission } & ModalProps;

export const EditMissionModal = ({
isOpen,
onClose,
mission,
}: EditModalProps) => {
const { id, contributionsDisabled, ...baseMission } = mission;
const initialState = useMemo(
() => ({
contributionsStartBlock: 0,
contributionsEndBlock: 0,
maxNumberOfContributions: 0,
...baseMission,
}),
[baseMission]
);

const signer = useSigner({ chainId: secondaryChain.id });

const db = useMemo(() => {
if (signer) return new Database({ signer });
}, [signer]);

const mutate = db
? (state: FormState) => {
const {
name,
description,
tags,
requirements,
deliverables,
rewards,
contributionsStartBlock,
contributionsEndBlock,
maxNumberOfContributions,
} = state;

return db
.prepare(
`UPDATE ${missionsTable} SET name = ?, description = ?, tags = ?, requirements = ?, deliverables = ?, rewards = ?, contributions_start_block = ?, contributions_end_block = ?, max_number_of_contributions = ? WHERE id = ?`
)
.bind(
name,
description,
JSON.stringify(tags),
JSON.stringify(requirements),
JSON.stringify(deliverables),
JSON.stringify(rewards),
contributionsStartBlock,
contributionsEndBlock,
maxNumberOfContributions,
id
)
.run();
}
: undefined;

const [formState, setFormState] = useState<FormState>(initialState);

const isFormValid = useMemo(
() => isValid(formState) && !isEqual(initialState, formState),
[formState]
);

useEffect(() => {
if (isOpen) {
setFormState(initialState);
}
}, [isOpen, setFormState]);

return (
<BaseMissionModal
title="Edit Mission"
formState={formState}
setFormState={setFormState}
isFormValid={isFormValid}
isOpen={isOpen}
onClose={onClose}
onMutate={mutate}
/>
);
};
16 changes: 13 additions & 3 deletions garage/src/pages/Admin/MissionAdmin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
Tbody,
Textarea,
useToast,
useDisclosure,
} from "@chakra-ui/react";
import {
useContractRead,
Expand All @@ -46,6 +47,7 @@ import { truncateWalletAddress } from "../../utils/fmt";
import { as0xString } from "../../utils/types";
import { useMission, useContributions } from "../../hooks/useMissions";
import { secondaryChain, deployment } from "../../env";
import { EditMissionModal } from "../../components/CreateMissionModal";
import { abi } from "../../abis/MissionsManager";

const { missionContributionsTable, missionContractAddress } = deployment;
Expand Down Expand Up @@ -320,6 +322,8 @@ export const MissionAdmin = () => {
if (isSuccess && !isTxLoading) refreshContributionsStatus();
}, [isSuccess, isTxLoading, refreshContributionsStatus]);

const { isOpen, onClose, onOpen } = useDisclosure();

return (
<>
<ReviewContributionModal
Expand All @@ -328,6 +332,9 @@ export const MissionAdmin = () => {
contribution={reviewContribution}
onTransactionCompleted={refreshContributions}
/>
{mission && (
<EditMissionModal mission={mission} isOpen={isOpen} onClose={onClose} />
)}
<Flex
direction="column"
align="center"
Expand Down Expand Up @@ -360,7 +367,10 @@ export const MissionAdmin = () => {
# {mission.id}{mission.description}
</Heading>
<Divider pt={4} />
<Heading>Contributions</Heading>
<Button maxWidth="230px" onClick={onOpen}>
Edit Mission
</Button>
<Heading mt={8}>Contributions</Heading>
<Heading size="sm">
Contributions are:{" "}
<b>{contributionsDisabled ? "disabled" : "enabled"}</b>
Expand All @@ -384,14 +394,14 @@ export const MissionAdmin = () => {
)}
{contributions && (
<>
<Heading>Contributions pending review</Heading>
<Heading mt={8}>Contributions pending review</Heading>
<ContributionsTable
contributions={contributions.filter(
({ status }) => status === "pending_review"
)}
onReviewContribution={setReviewContribution}
/>
<Heading>Reviewed</Heading>
<Heading mt={8}>Reviewed</Heading>
<ContributionsTable
contributions={contributions.filter(
({ status }) => status !== "pending_review"
Expand Down

0 comments on commit 01c0aae

Please sign in to comment.