Skip to content

Commit

Permalink
Merge pull request #214 from alleslabs/feat/permission-save-code
Browse files Browse the repository at this point in the history
feat: permission save new code
  • Loading branch information
songwongtp authored Feb 23, 2023
2 parents 2a1bcf4 + 08feac9 commit 6feaeea
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 103 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#214](https://github.com/alleslabs/celatone-frontend/pull/214) Show code permission helper text in save new code modal
- [#218](https://github.com/alleslabs/celatone-frontend/pull/218) Add instantiated and admin contracts of an account
- [#192](https://github.com/alleslabs/celatone-frontend/pull/192) Add alternative sidebar with only icons
- [#210](https://github.com/alleslabs/celatone-frontend/pull/210) New design for token card, currently support price
Expand Down
15 changes: 13 additions & 2 deletions src/lib/components/PermissionChip.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { chakra, Tag } from "@chakra-ui/react";
import { chakra, Tag, Tooltip } from "@chakra-ui/react";
import { useWallet } from "@cosmos-kit/react";
import type { CSSProperties } from "react";

import type { HumanAddr, PermissionAddresses } from "lib/types";
import { InstantiatePermission } from "lib/types";
import { getPermissionHelper } from "lib/utils";

const StyledTag = chakra(Tag, {
baseStyle: {
Expand Down Expand Up @@ -34,5 +35,15 @@ export const PermissionChip = ({
? "honeydew.darker"
: "pebble.700";

return <StyledTag bgColor={tagBgColor}>{instantiatePermission}</StyledTag>;
const { message } = getPermissionHelper(
address as HumanAddr,
instantiatePermission,
permissionAddresses
);

return (
<Tooltip hasArrow label={message} placement="top" bg="honeydew.darker">
<StyledTag bgColor={tagBgColor}>{instantiatePermission}</StyledTag>
</Tooltip>
);
};
17 changes: 14 additions & 3 deletions src/lib/components/forms/FormStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type ResponseState = "init" | "loading" | "success" | "error";
export interface FormStatus {
state: ResponseState;
message?: string;
messageColor?: string;
}

export const getStatusIcon = (state: ResponseState, boxSize = "1em") => {
Expand All @@ -27,12 +28,22 @@ export const getStatusIcon = (state: ResponseState, boxSize = "1em") => {
export const getResponseMsg = (statusInfo: FormStatus, helperText = "") => {
switch (statusInfo.state) {
case "success":
return <Text color="success.main">{statusInfo.message}</Text>;
return (
<Text color={statusInfo.messageColor ?? "success.main"}>
{statusInfo.message}
</Text>
);
case "error":
return <Text color="error.main">{statusInfo.message}</Text>;
return (
<Text color={statusInfo.messageColor ?? "error.main"}>
{statusInfo.message}
</Text>
);
case "init":
case "loading":
default:
return <Text color="text.dark">{helperText}</Text>;
return (
<Text color={statusInfo.messageColor ?? "text.dark"}>{helperText}</Text>
);
}
};
23 changes: 10 additions & 13 deletions src/lib/components/forms/NumberInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
FormHelperText,
FormLabel,
Input,
Text,
InputGroup,
InputRightElement,
Box,
} from "@chakra-ui/react";
import type { FormControlProps } from "@chakra-ui/react";
import type { HTMLInputTypeAttribute, ChangeEvent } from "react";
Expand Down Expand Up @@ -81,18 +81,15 @@ export const NumberInput = ({
)}
</InputGroup>

<FormErrorMessage>{error}</FormErrorMessage>
{error ? (
<FormErrorMessage className="error-text">{error}</FormErrorMessage>
) : (
<FormHelperText className="helper-text">
{status ? (
getResponseMsg(status, helperText)
) : (
<Text color="text.dark">{helperText}</Text>
)}
</FormHelperText>
)}
<Box mt={1}>
{error ? (
<FormErrorMessage className="error-text">{error}</FormErrorMessage>
) : (
<FormHelperText className="helper-text">
{status?.message ? getResponseMsg(status, helperText) : helperText}
</FormHelperText>
)}
</Box>
</FormControl>
);
};
45 changes: 27 additions & 18 deletions src/lib/components/modal/code/CodeDetailsTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import { MdAddCircleOutline, MdCheckCircle } from "react-icons/md";
import { ActionModal } from "..";
import { ExplorerLink } from "lib/components/ExplorerLink";
import { TextInput } from "lib/components/forms";
import { PermissionChip } from "lib/components/PermissionChip";
import { MAX_CODE_NAME_LENGTH } from "lib/data";
import { useCodeStore, useGetAddressType } from "lib/hooks";
import { AmpEvent, AmpTrack } from "lib/services/amplitude";
import type { CodeLocalInfo } from "lib/stores/code";
import type { Addr } from "lib/types";
import type { Addr, CodeInfo } from "lib/types";

interface CodeDetailsTemplateModalProps {
title: string;
helperText?: string;
mainBtnTitle: string;
isNewCode: boolean;
codeLocalInfo: CodeLocalInfo;
codeInfo: CodeInfo;
triggerElement: JSX.Element;
}

Expand All @@ -25,26 +25,26 @@ export const CodeDetailsTemplateModal = ({
helperText,
mainBtnTitle,
isNewCode,
codeLocalInfo,
codeInfo,
triggerElement,
}: CodeDetailsTemplateModalProps) => {
const { saveNewCode, updateCodeInfo } = useCodeStore();
const toast = useToast();
const getAddressType = useGetAddressType();

const [name, setName] = useState(codeLocalInfo.name ?? "");
const [name, setName] = useState(codeInfo.name ?? "");

const uploaderType = getAddressType(codeLocalInfo.uploader);
const uploaderType = getAddressType(codeInfo.uploader);

const handleAction = useCallback(() => {
if (isNewCode) {
AmpTrack(AmpEvent.CODE_SAVE);
saveNewCode(codeLocalInfo.id);
saveNewCode(codeInfo.id);
} else {
AmpTrack(AmpEvent.CODE_EDIT);
}

updateCodeInfo(codeLocalInfo.id, codeLocalInfo.uploader as Addr, name);
updateCodeInfo(codeInfo.id, codeInfo.uploader as Addr, name);

// TODO: abstract toast to template later
toast({
Expand All @@ -64,8 +64,8 @@ export const CodeDetailsTemplateModal = ({
),
});
}, [
codeLocalInfo.id,
codeLocalInfo.uploader,
codeInfo.id,
codeInfo.uploader,
name,
isNewCode,
saveNewCode,
Expand All @@ -76,8 +76,8 @@ export const CodeDetailsTemplateModal = ({

// fix prefilling blank space problem (e.g. name saved as " ")
useEffect(() => {
setName(codeLocalInfo.name ?? "");
}, [codeLocalInfo.name]);
setName(codeInfo.name ?? "");
}, [codeInfo.name]);

return (
<ActionModal
Expand All @@ -90,23 +90,32 @@ export const CodeDetailsTemplateModal = ({
mainBtnTitle={mainBtnTitle}
mainAction={handleAction}
headerContent={
<Flex direction="column">
<Flex direction="column" gap={2}>
{helperText && (
<Text variant="body1" mt={6}>
{helperText}
</Text>
)}
<Flex align="center" mb={2} mt={6}>
<Text variant="body2" fontWeight={700} w="20%">
<Flex align="center" mt={4}>
<Text variant="body2" fontWeight={700} w="30%">
Code ID
</Text>
<ExplorerLink type="code_id" value={codeLocalInfo.id.toString()} />
<ExplorerLink type="code_id" value={codeInfo.id.toString()} />
</Flex>
<Flex align="center">
<Text variant="body2" fontWeight={700} w="20%">
<Text variant="body2" fontWeight={700} w="30%">
Uploader
</Text>
<ExplorerLink type={uploaderType} value={codeLocalInfo.uploader} />
<ExplorerLink type={uploaderType} value={codeInfo.uploader} />
</Flex>
<Flex align="center">
<Text variant="body2" fontWeight={700} w="30%">
Instantiate Permission
</Text>
<PermissionChip
instantiatePermission={codeInfo.instantiatePermission}
permissionAddresses={codeInfo.permissionAddresses}
/>
</Flex>
</Flex>
}
Expand Down
8 changes: 4 additions & 4 deletions src/lib/components/modal/code/EditCodeDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import type { CodeLocalInfo } from "lib/stores/code";
import type { CodeInfo } from "lib/types";

import { CodeDetailsTemplateModal } from "./CodeDetailsTemplate";

interface EditCodeDetailsModalProps {
codeLocalInfo: CodeLocalInfo;
codeInfo: CodeInfo;
triggerElement: JSX.Element;
}
export const EditCodeDetailsModal = ({
codeLocalInfo,
codeInfo,
triggerElement,
}: EditCodeDetailsModalProps) => (
<CodeDetailsTemplateModal
title="Edit Code Name"
mainBtnTitle="Save"
isNewCode={false}
codeLocalInfo={codeLocalInfo}
codeInfo={codeInfo}
triggerElement={triggerElement}
/>
);
8 changes: 4 additions & 4 deletions src/lib/components/modal/code/SaveCodeDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import type { CodeLocalInfo } from "lib/stores/code";
import type { CodeInfo } from "lib/types";

import { CodeDetailsTemplateModal } from "./CodeDetailsTemplate";

interface SaveCodeDetailsModalProps {
codeLocalInfo: CodeLocalInfo;
codeInfo: CodeInfo;
triggerElement: JSX.Element;
}
export const SaveCodeDetailsModal = ({
codeLocalInfo,
codeInfo,
triggerElement,
}: SaveCodeDetailsModalProps) => (
<CodeDetailsTemplateModal
title="Save New Code"
helperText={`Save other stored codes to your "Saved Codes" list`}
mainBtnTitle="Save New Code"
isNewCode
codeLocalInfo={codeLocalInfo}
codeInfo={codeInfo}
triggerElement={triggerElement}
/>
);
19 changes: 16 additions & 3 deletions src/lib/components/modal/code/SaveNewCode.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ButtonProps } from "@chakra-ui/react";
import { Button, Icon, useToast, FormControl } from "@chakra-ui/react";
import { useWallet } from "@cosmos-kit/react";
import { useQuery } from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import { MdBookmark, MdCheckCircle } from "react-icons/md";
Expand All @@ -11,14 +12,15 @@ import { getMaxCodeNameLengthError, MAX_CODE_NAME_LENGTH } from "lib/data";
import { useCodeStore, useLCDEndpoint } from "lib/hooks";
import { AmpEvent, AmpTrack } from "lib/services/amplitude";
import { getCodeIdInfo } from "lib/services/code";
import type { Addr } from "lib/types";
import { getNameAndDescriptionDefault } from "lib/utils";
import type { Addr, HumanAddr } from "lib/types";
import { getNameAndDescriptionDefault, getPermissionHelper } from "lib/utils";

interface SaveNewCodeModalProps {
buttonProps: ButtonProps;
}

export function SaveNewCodeModal({ buttonProps }: SaveNewCodeModalProps) {
const { address } = useWallet();
/* STATE */
const [codeId, setCodeId] = useState("");
const [codeIdStatus, setCodeIdStatus] = useState<FormStatus>({
Expand Down Expand Up @@ -60,7 +62,18 @@ export function SaveNewCodeModal({ buttonProps }: SaveNewCodeModalProps) {
retry: false,
cacheTime: 0,
onSuccess(data) {
setCodeIdStatus({ state: "success", message: "Valid Code ID" });
const { message, messageColor } = getPermissionHelper(
address as HumanAddr,
data.code_info.instantiate_permission.permission,
data.code_info.instantiate_permission.address
? [data.code_info.instantiate_permission.address]
: data.code_info.instantiate_permission.addresses
);
setCodeIdStatus({
state: "success",
message: `${message} (${data.code_info.instantiate_permission.permission})`,
messageColor,
});
setUploader(data.code_info.creator);
setUploaderStatus({ state: "success" });
},
Expand Down
10 changes: 5 additions & 5 deletions src/lib/components/modal/code/SaveOrEditCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { Button, chakra, Icon } from "@chakra-ui/react";
import { observer } from "mobx-react-lite";
import { MdBookmarkBorder, MdMode } from "react-icons/md";

import type { CodeLocalInfo } from "lib/stores/code";
import type { CodeInfo } from "lib/types";

import { EditCodeDetailsModal } from "./EditCodeDetails";
import { SaveCodeDetailsModal } from "./SaveCodeDetails";

interface SaveOrEditCodeModalProps {
mode: "save" | "edit";
codeLocalInfo: CodeLocalInfo;
codeInfo: CodeInfo;
}

const StyledIcon = chakra(Icon, {
Expand All @@ -19,10 +19,10 @@ const StyledIcon = chakra(Icon, {
});

export const SaveOrEditCodeModal = observer(
({ mode, codeLocalInfo }: SaveOrEditCodeModalProps) => {
({ mode, codeInfo }: SaveOrEditCodeModalProps) => {
return mode === "save" ? (
<SaveCodeDetailsModal
codeLocalInfo={codeLocalInfo}
codeInfo={codeInfo}
triggerElement={
<Button
variant="outline-gray"
Expand All @@ -34,7 +34,7 @@ export const SaveOrEditCodeModal = observer(
/>
) : (
<EditCodeDetailsModal
codeLocalInfo={codeLocalInfo}
codeInfo={codeInfo}
triggerElement={
<Button variant="ghost-gray" leftIcon={<StyledIcon as={MdMode} />}>
Edit
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/modal/code/SaveOrRemoveCode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function SaveOrRemoveCodeModal({
/>
) : (
<SaveCodeDetailsModal
codeLocalInfo={codeInfo}
codeInfo={codeInfo}
triggerElement={
<StyledIconButton
icon={<MdBookmarkBorder />}
Expand Down
Loading

2 comments on commit 6feaeea

@vercel
Copy link

@vercel vercel bot commented on 6feaeea Feb 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 6feaeea Feb 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.