Skip to content

Commit

Permalink
fix: conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
poomthiti committed Feb 2, 2023
2 parents 67996c8 + c59f13e commit edf0451
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 82 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased

### Features

- [#149](https://github.com/alleslabs/celatone-frontend/pull/149) Apply new branding

- [#93](https://github.com/alleslabs/celatone-frontend/pull/93) Add filter code by instantiate permission in all codes page
- [#141](https://github.com/alleslabs/celatone-frontend/pull/141) Add 404 not found page, catch network params error
- [#134](https://github.com/alleslabs/celatone-frontend/pull/134) Fix un-align sub-page with sidebar
- [#144](https://github.com/alleslabs/celatone-frontend/pull/144) Add `Assign me` for admin address on instantiate form
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/InputWithIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ const InputWithIcon = ({
onChange={onChange}
size={size}
/>
<InputRightElement h="full">
<SearchIcon color="input.main" />
<InputRightElement h="56px" alignItems="center">
<SearchIcon color="gray.600" />
</InputRightElement>
</InputGroup>
);
Expand Down
61 changes: 61 additions & 0 deletions src/lib/components/forms/FilterByPermission.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Grid } from "@chakra-ui/react";
import type { IconType } from "react-icons";
import { MdCheck, MdHowToVote, MdPerson } from "react-icons/md";

import type { PermissionFilterValue } from "lib/hooks";

import { SelectInput } from "./SelectInput";

interface PermissionOption {
label: string;
value: PermissionFilterValue;
disabled: boolean;
icon?: IconType;
iconColor: string;
}

interface FilterByPermissionProps {
setPermissionValue: (newVal: PermissionFilterValue) => void;
initialSelected: string;
}

const options: PermissionOption[] = [
{
label: "All",
value: "all",
disabled: false,
icon: MdCheck,
iconColor: "gray.600",
},
{
label: "Can Instantiate without proposal",
value: "without-proposal",
disabled: false,
icon: MdPerson,
iconColor: "primary.main",
},
{
label: "Instantiate through proposal only",
value: "with-proposal",
disabled: false,
icon: MdHowToVote,
iconColor: "text.dark",
},
];

export const FilterByPermission = ({
setPermissionValue,
initialSelected,
}: FilterByPermissionProps) => {
return (
<Grid columnGap="16px" w="full" mb="16px" maxW="360px">
<SelectInput<PermissionFilterValue>
formLabel="Filter by Instantiate Permission"
options={options}
onChange={setPermissionValue}
placeholder="Select"
initialSelected={initialSelected}
/>
</Grid>
);
};
68 changes: 50 additions & 18 deletions src/lib/components/forms/SelectInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@ import {
Popover,
PopoverTrigger,
PopoverContent,
Box,
useDisclosure,
useOutsideClick,
Flex,
InputLeftElement,
} from "@chakra-ui/react";
import type { MutableRefObject, ReactNode } from "react";
import { useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import type { IconType } from "react-icons/lib";
import { MdArrowDropDown } from "react-icons/md";

const ITEM_HEIGHT = 57;
import type { Option } from "lib/types";

interface SelectInputProps {
const ITEM_HEIGHT = 56;

interface SelectInputProps<T extends string> {
formLabel?: string;
options: { label: string; value: string; disabled: boolean }[];
onChange: (newVal: string) => void;
options: {
label: string;
value: T;
disabled: boolean;
icon?: IconType;
iconColor?: string;
}[];
onChange: (newVal: T) => void;
placeholder?: string;
initialSelected: string;
hasDivider?: boolean;
}

interface SelectItemProps {
Expand All @@ -32,40 +43,49 @@ interface SelectItemProps {

const SelectItem = ({ children, onSelect, disabled }: SelectItemProps) => {
return (
<Box
p={4}
<Flex
px={4}
py={2}
onClick={onSelect}
color="text.main"
cursor="pointer"
gap={2}
aria-disabled={disabled}
_hover={{ bg: "pebble.800" }}
transition="all .25s ease-in-out"
_disabled={{ opacity: 0.4, pointerEvents: "none" }}
>
{children}
</Box>
</Flex>
);
};

export const SelectInput = ({
export const SelectInput = <T extends string>({
formLabel,
options,
onChange,
placeholder = "",
initialSelected,
}: SelectInputProps) => {
hasDivider = false,
}: SelectInputProps<T>) => {
const optionRef = useRef() as MutableRefObject<HTMLElement>;
const { isOpen, onClose, onOpen } = useDisclosure();

const inputRef = useRef() as MutableRefObject<HTMLInputElement>;
const [selected, setSelected] = useState(
() => options.find((asset) => asset.value === initialSelected)?.label ?? ""
() => options.find((item) => item.value === initialSelected)?.label ?? ""
);

const [inputRefWidth, setInputRefWidth] = useState<Option<number>>();
useOutsideClick({
ref: optionRef,
handler: () => isOpen && onClose(),
});
const selectedOption = options.find((item) => item.label === selected);

useEffect(() => {
if (inputRef.current) {
setInputRefWidth(inputRef.current.clientWidth);
}
}, [inputRef]);
return (
<Popover placement="bottom-start" isOpen={isOpen}>
<PopoverTrigger>
Expand All @@ -92,13 +112,24 @@ export const SelectInput = ({
}}
>
<div className="form-label">{formLabel}</div>
{selectedOption?.icon && (
<InputLeftElement pointerEvents="none" h="full">
<Icon
as={selectedOption.icon}
color={selectedOption.iconColor}
fontSize="20px"
/>
</InputLeftElement>
)}
<Input
size="lg"
textAlign="start"
type="button"
value={selected || placeholder}
fontSize="14px"
color={selected ? "text.main" : "text.dark"}
ref={inputRef}
pl={selectedOption?.icon ? 9 : 4}
/>
<InputRightElement pointerEvents="none" h="full">
<Icon as={MdArrowDropDown} color="pebble.600" fontSize="24px" />
Expand All @@ -109,7 +140,7 @@ export const SelectInput = ({
ref={optionRef}
border="unset"
bg="pebble.900"
w="200px"
w={inputRefWidth}
maxH={`${ITEM_HEIGHT * 4}px`}
overflow="scroll"
borderRadius="8px"
Expand All @@ -118,12 +149,12 @@ export const SelectInput = ({
}}
sx={{
"> div:not(:last-of-type)": {
borderBottom: "1px solid",
borderBottomColor: "pebble.700",
borderBottom: hasDivider && "1px solid",
borderBottomColor: hasDivider && "pebble.700",
},
}}
>
{options.map(({ label, value, disabled }) => (
{options.map(({ label, value, disabled, icon, iconColor }) => (
<SelectItem
key={value}
onSelect={() => {
Expand All @@ -133,6 +164,7 @@ export const SelectInput = ({
}}
disabled={disabled}
>
{icon && <Icon as={icon} boxSize={5} color={iconColor} />}
{label}
</SelectItem>
))}
Expand Down
1 change: 1 addition & 0 deletions src/lib/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from "./useLCDEndpoint";
export * from "./useUserKey";
export * from "./useDummyWallet";
export * from "./useAddress";
export * from "./useCodeFilter";
46 changes: 46 additions & 0 deletions src/lib/hooks/useCodeFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useWallet } from "@cosmos-kit/react";
import { useCallback } from "react";

import type { CodeInfo, HumanAddr } from "lib/types";
import { InstantiatePermission } from "lib/types";

export type PermissionFilterValue =
| "all"
| "without-proposal"
| "with-proposal";

export const usePermissionFilter = (filterValue?: PermissionFilterValue) => {
const { address } = useWallet();
return useCallback(
({ instantiatePermission, permissionAddresses }: CodeInfo) => {
const isAllowed =
permissionAddresses.includes(address as HumanAddr) ||
instantiatePermission === InstantiatePermission.EVERYBODY;

switch (filterValue) {
case "with-proposal":
return !isAllowed;
case "without-proposal":
return isAllowed;
case "all":
default:
return true;
}
},
[address, filterValue]
);
};

export const useSearchFilter = (keyword = "") => {
return useCallback(
(code: CodeInfo) => {
const computedKeyword = keyword.trim();
if (!computedKeyword.length) return true;
return (
code.id.toString().startsWith(computedKeyword) ||
code.description?.toLowerCase().includes(computedKeyword.toLowerCase())
);
},
[keyword]
);
};
27 changes: 12 additions & 15 deletions src/lib/pages/all-codes/data.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo } from "react";

import { useCodeStore } from "lib/hooks";
import type { PermissionFilterValue } from "lib/hooks";
import { useCodeStore, usePermissionFilter, useSearchFilter } from "lib/hooks";
import { useCodeListQuery } from "lib/services/codeService";
import type { CodeInfo } from "lib/types";

Expand All @@ -9,9 +10,14 @@ interface AllCodesData {
isLoading: boolean;
}

export const useAllCodesData = (keyword?: string): AllCodesData => {
export const useAllCodesData = (
keyword: string,
permissionValue: PermissionFilterValue
): AllCodesData => {
const { getCodeLocalInfo, isCodeIdSaved } = useCodeStore();
const { data: rawAllCodes = [], isLoading } = useCodeListQuery();
const permissionFilterFn = usePermissionFilter(permissionValue);
const searchFilterFn = useSearchFilter(keyword);

const allCodes = rawAllCodes.map<CodeInfo>((code) => ({
...code,
Expand All @@ -20,18 +26,9 @@ export const useAllCodesData = (keyword?: string): AllCodesData => {
}));

return useMemo(() => {
const filterFn = (code: CodeInfo) => {
if (keyword === undefined) return true;

const computedKeyword = keyword.trim();
if (computedKeyword.length === 0) return true;

return (
code.id.toString().startsWith(computedKeyword) ||
code.description?.toLowerCase().includes(computedKeyword.toLowerCase())
);
return {
allCodes: allCodes.filter(permissionFilterFn).filter(searchFilterFn),
isLoading,
};

return { allCodes: allCodes.filter(filterFn), isLoading };
}, [keyword, allCodes, isLoading]);
}, [allCodes, isLoading, permissionFilterFn, searchFilterFn]);
};
Loading

0 comments on commit edf0451

Please sign in to comment.