Skip to content

Commit

Permalink
Improve SelectInput
Browse files Browse the repository at this point in the history
  • Loading branch information
henriqueleite42 committed Nov 19, 2023
1 parent a1239e5 commit d374221
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 59 deletions.
29 changes: 25 additions & 4 deletions src/components/AddTransaction/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,29 @@ import { TextInput } from "components/Inputs/Text";
import { TextareaInput } from "components/Inputs/Textarea";
import { Space } from "components/Space";
import { useAddTransaction } from "contexts/add-transaction";
import { CardTypeEnum } from "types/enums/card-type";
import { TransactionTypeEnum } from "types/enums/transaction-type";

const categories = Object.values(categoriesData);
const paymentMethods = [
...Object.values(cards).map((c) => ({
id: `${c.cardId}#CARD`,
color: c.cardProvider.color,
name: c.cardProvider.name,
iconUrl: c.cardProvider.iconUrl,
groupLabel:
c.cardProvider.type === CardTypeEnum.POSTPAID
? "Cartões de crédito"
: "Vales",
})),
...Object.values(bankAccounts).map((b) => ({
id: `${b.bankAccountId}#BANK`,
color: b.bank.color,
name: b.bank.name,
iconUrl: b.bank.iconUrl,
groupLabel: "Contas bancárias",
})),
];

export const AddTransaction = () => {
const {
Expand Down Expand Up @@ -116,12 +136,13 @@ export const AddTransaction = () => {
label="Método de pagamento"
toBeSelectedLabel="Selecione o método de pagamento"
value={data.paymentMethodId}
data={Object.values(cards)}
data={paymentMethods}
fieldNames={{
id: "cardId",
color: "cardProvider.color",
id: "id",
color: "color",
label: "name",
iconUrl: "cardProvider.iconUrl",
iconUrl: "iconUrl",
groupLabel: "groupLabel",
}}
onChange={(val) => setData("paymentMethodId", val)}
/>
Expand Down
149 changes: 94 additions & 55 deletions src/components/Inputs/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Listbox, Transition } from "@headlessui/react";
import { colors } from "assets/colors";
import { Icon } from "components/Icon";
import { Icon, IconType } from "components/Icon";
import React from "react";
import { getTextColor } from "utils/color";
import { val } from "utils/utils";

interface Props<T> {
id: string;
Expand All @@ -17,6 +18,7 @@ interface Props<T> {
color?: Leaves<T>;
icon?: Leaves<T>;
iconUrl?: Leaves<T>;
groupLabel?: Leaves<T>;
};
onChange: (val: any) => void;
}
Expand All @@ -31,7 +33,26 @@ export function SelectInput<T extends Record<string, any>>({
disabled,
onChange,
}: Props<T>) {
const selected = data.find((d) => d[fieldNames.id] === value);
const selected = data.find((d) => val<string>(d, fieldNames.id) === value);

const groups: Array<[string, Array<T>]> = fieldNames.groupLabel
? Object.entries(
data.reduce(
(acc, cur) => {
const key = val<string>(cur, fieldNames.groupLabel!);

if (!acc[key]) {
acc[key] = [];
}

acc[key].push(cur);

return acc;
},
{} as Record<string, Array<T>>,
),
)
: [["", data]];

return (
<Listbox name={id} disabled={disabled} value={selected} onChange={onChange}>
Expand Down Expand Up @@ -65,11 +86,11 @@ export function SelectInput<T extends Record<string, any>>({
selected
? {
backgroundColor: fieldNames.color
? selected[fieldNames.color]
? val<string>(selected, fieldNames.color)
: colors.primary,
color: getTextColor(
fieldNames.color
? selected[fieldNames.color]
? val<string>(selected, fieldNames.color)
: colors.primary,
),
}
Expand All @@ -87,17 +108,20 @@ export function SelectInput<T extends Record<string, any>>({
{selected && (
<span className="flex items-center">
{fieldNames.icon && (
<Icon icon={selected[fieldNames.icon]} size={2} />
<Icon
icon={val<IconType>(selected, fieldNames.icon)}
size={2}
/>
)}
{fieldNames.iconUrl && (
<img
src={selected[fieldNames.iconUrl]}
alt={selected[fieldNames.label]}
src={val<string>(selected, fieldNames.iconUrl)}
alt={val<string>(selected, fieldNames.label)}
className="max-w-4 max-h-4"
/>
)}
<span className="ml-3 block truncate">
{selected[fieldNames.label]}
{val<string>(selected, fieldNames.label)}
</span>
</span>
)}
Expand Down Expand Up @@ -135,53 +159,68 @@ export function SelectInput<T extends Record<string, any>>({
"sm:text-sm",
].join(" ")}
>
{data.map((d) => (
<Listbox.Option
key={d[fieldNames.id]}
className="relative cursor-default select-none py-1 pl-3 pr-12"
value={d[fieldNames.id]}
>
<div
className="flex items-center rounded px-4 py-2"
style={
d[fieldNames.id] === value
? {
backgroundColor: fieldNames.color
? d[fieldNames.color]
: colors.primary,
color: getTextColor(
fieldNames.color
? d[fieldNames.color]
: colors.primary,
),
}
: {
border: `1px solid ${
fieldNames.color
? d[fieldNames.color]
: colors.primary
}`,
color: fieldNames.color
? d[fieldNames.color]
: colors.primary,
}
}
>
{fieldNames.icon && d[fieldNames.icon] && (
<Icon icon={d[fieldNames?.icon]} size={2} />
)}
{fieldNames.iconUrl && d[fieldNames.iconUrl] && (
<img
src={d[fieldNames?.iconUrl]}
alt={d[fieldNames.label]}
className="max-w-4 max-h-4"
/>
)}
<span className="ml-3 block truncate font-semibold">
{d[fieldNames?.label]}
</span>
</div>
</Listbox.Option>
{groups.map(([groupLabel, items]) => (
<>
{groupLabel && (
<div className="px-3 py-1 bg-gray font-bold">
{groupLabel}
</div>
)}

{items.map((d) => (
<Listbox.Option
key={val<string>(d, fieldNames.id)}
className="relative cursor-default select-none py-1 pl-3 pr-12"
value={d[fieldNames.id]}
>
<div
className="flex items-center rounded px-4 py-2"
style={
val<string>(d, fieldNames.id) === value
? {
backgroundColor: fieldNames.color
? val<string>(d, fieldNames.color)
: colors.primary,
color: getTextColor(
fieldNames.color
? val<string>(d, fieldNames.color)
: colors.primary,
),
}
: {
border: `1px solid ${
fieldNames.color
? val<string>(d, fieldNames.color)
: colors.primary
}`,
color: fieldNames.color
? val<string>(d, fieldNames.color)
: colors.primary,
}
}
>
{fieldNames.icon &&
val<IconType>(d, fieldNames.icon) && (
<Icon
icon={val<IconType>(d, fieldNames.icon)}
size={2}
/>
)}
{fieldNames.iconUrl &&
val<string>(d, fieldNames.iconUrl) && (
<img
src={val<string>(d, fieldNames.iconUrl)}
alt={val<string>(d, fieldNames.label)}
className="max-w-4 max-h-4"
/>
)}
<span className="ml-3 block truncate font-semibold">
{val<string>(d, fieldNames.label)}
</span>
</div>
</Listbox.Option>
))}
</>
))}
</Listbox.Options>
</Transition>
Expand Down
14 changes: 14 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const val = <T = unknown>(obj: Record<string, any>, path: string): T => {
const paths = path.split(".");
let current = obj;

for (let i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined as T;
} else {
current = current[paths[i]];
}
}

return current as T;
};

0 comments on commit d374221

Please sign in to comment.