Skip to content

Commit

Permalink
feat(header): use nextui accordion for channel-list (#793)
Browse files Browse the repository at this point in the history
* feat(home): use nextui accordion for channel-list

* feat(home): use further nextui components channel-list

* feat(home): use further nextui components channel-list

* fix(home): html-nesting warning
  • Loading branch information
escapedcat authored Nov 11, 2024
1 parent d9d8faa commit c3bf764
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 133 deletions.
9 changes: 8 additions & 1 deletion src/components/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface Props extends HTMLAttributes<HTMLElement> {
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "div";
children: ReactNode;
color?: Colors;
className?: string;
}

const colors = {
Expand All @@ -16,14 +17,20 @@ const colors = {

type Colors = keyof typeof colors;

export const Alert = ({ as = "p", color = "success", children }: Props) => {
export const Alert = ({
as = "p",
color = "success",
className,
children,
}: Props) => {
const Component = as;

return (
<Component
className={twMerge(
"rounded-xl border p-4 text-center font-semibold",
colors[color],
className,
)}
>
{children}
Expand Down
16 changes: 0 additions & 16 deletions src/components/Message.tsx

This file was deleted.

167 changes: 74 additions & 93 deletions src/pages/Home/ListChannelModal/Channel.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import { Alert } from "@/components/Alert";
import { AppContext, Unit } from "@/context/app-context";
import { LightningChannel } from "@/models/lightning-channel";
import { convertSatToBtc, convertToString } from "@/utils/format";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
import { Checkbox } from "@nextui-org/checkbox";
import { Button } from "@nextui-org/react";
import { FC, useContext, useRef, useState } from "react";
import { FC, useContext, useState } from "react";
import { useTranslation } from "react-i18next";

type Props = {
isLoading: boolean;
showDetails: boolean;
channel: LightningChannel;
onClick: (channelId: string) => void;
onDelete: (channelId: string, forceClose: boolean) => void;
};

const Channel: FC<Props> = ({
isLoading,
showDetails,
channel,
onClick,
onDelete,
}) => {
const { unit } = useContext(AppContext);
const Channel: FC<Props> = ({ isLoading, channel, onDelete }) => {
const { t } = useTranslation();
const { unit } = useContext(AppContext);
const [confirm, setConfirm] = useState(false);
const forceCloseEl = useRef<HTMLInputElement>(null);
const [isForceClose, setIsForceClose] = useState(false);

const convertedLocal =
unit === Unit.SAT
Expand All @@ -35,95 +28,83 @@ const Channel: FC<Props> = ({
? convertToString(unit, channel.balance_remote)
: convertSatToBtc(channel.balance_remote);

const clickHandler = () => {
setConfirm(false);
onClick(channel.channel_id);
};

const closeChannelHandler = () => {
onDelete(channel.channel_id, forceCloseEl.current?.checked || false);
onDelete(channel.channel_id, isForceClose);
};

return (
<li className="bg-gray-700 p-3 shadow-inner hover:bg-gray-600">
<div
className="flex justify-between border-b border-gray-500 pb-2"
onClick={clickHandler}
>
<span>{channel.peer_alias}</span>
{showDetails && <ChevronUpIcon className="h-6 w-6" />}
{!showDetails && <ChevronDownIcon className="h-6 w-6" />}
</div>
<section className="flex flex-col gap-4 py-4">
<article className="flex flex-col items-center justify-center md:flex-row md:justify-around">
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.channel_id")}</h4>
<p className="mx-2 overflow-x-auto">{channel.channel_id}</p>
</div>
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.active")}</h4>
<p className="mx-2 overflow-x-auto">
{channel.active ? t("setup.yes") : t("home.no")}
</p>
</div>
</article>
<article className="flex flex-col items-center justify-center md:flex-row md:justify-around">
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.local_balance")}</h4>
<p className="mx-2 overflow-x-auto">
{convertedLocal} {unit}
</p>
</div>
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.remote_balance")}</h4>
<p className="mx-2 overflow-x-auto">
{convertedRemote} {unit}
</p>
</div>
</article>

{showDetails && (
<section className="flex flex-col gap-4 py-4">
<article className="flex flex-col items-center justify-center md:flex-row md:justify-around">
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.channel_id")}</h4>
<p className="mx-2 overflow-x-auto">{channel.channel_id}</p>
</div>
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.active")}</h4>
<p className="mx-2 overflow-x-auto">
{channel.active ? t("setup.yes") : t("home.no")}
</p>
</div>
</article>
<article className="flex flex-col items-center justify-center md:flex-row md:justify-around">
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.local_balance")}</h4>
<p className="mx-2 overflow-x-auto">
{convertedLocal} {unit}
</p>
</div>
<div className="mb-1 flex w-full flex-col justify-center md:w-1/2 md:justify-around">
<h4 className="mb-1 font-bold">{t("home.remote_balance")}</h4>
<p className="mx-2 overflow-x-auto">
{convertedRemote} {unit}
</p>
</div>
</article>

<article>
<Button
color="primary"
isDisabled={confirm}
onClick={() => setConfirm(true)}
>
{t("home.close_channel")}
</Button>
<article>
<Button
color="primary"
isDisabled={confirm}
onClick={() => setConfirm(true)}
>
{t("home.close_channel")}
</Button>

{/*TODO should be confirm modal*/}
{confirm && (
<div className="flex flex-col justify-center gap-4">
<span>{t("home.confirm_channel_close")}</span>
{/* TODO should be confirm modal maybe? */}
{confirm && (
<Alert color="danger" className="mt-4" as="div">
<div className="flex flex-col justify-center gap-4">
<p>{t("home.confirm_channel_close")}</p>

<div className="flex items-center justify-center gap-2">
<label htmlFor="forceClose">{t("home.force_close")}</label>
<input id="forceClose" type="checkbox" ref={forceCloseEl} />
</div>
<div className="flex items-center justify-center gap-2">
<Checkbox
isSelected={isForceClose}
onValueChange={setIsForceClose}
>
{t("home.force_close")}
</Checkbox>
</div>

<div className="flex justify-center gap-4">
<Button
onClick={() => setConfirm(false)}
isDisabled={isLoading}
>
{t("setup.cancel")}
</Button>
<Button
color="primary"
isLoading={isLoading}
onClick={closeChannelHandler}
>
{t("setup.yes")}
</Button>
</div>
<div className="flex justify-center gap-4">
<Button
onClick={() => setConfirm(false)}
isDisabled={isLoading}
>
{t("setup.cancel")}
</Button>
<Button
color="primary"
isLoading={isLoading}
onClick={closeChannelHandler}
>
{t("setup.yes")}
</Button>
</div>
)}
</article>
</section>
)}
</li>
</div>
</Alert>
)}
</article>
</section>
);
};

Expand Down
31 changes: 10 additions & 21 deletions src/pages/Home/ListChannelModal/ChannelList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Channel from "./Channel";
import { LightningChannel } from "@/models/lightning-channel";
import { FC, useState } from "react";
import { Accordion, AccordionItem } from "@nextui-org/react";
import { FC } from "react";

type Props = {
isLoading: boolean;
Expand All @@ -9,30 +10,18 @@ type Props = {
};

const ChannelList: FC<Props> = ({ isLoading, channel, onDelete }) => {
const [showDetails, setShowDetails] = useState<string | null>(null);

const toggleDetailHandler = (channelId: string) => {
setShowDetails((prev) => {
if (prev === channelId) {
return null;
}
return channelId;
});
};

return (
<ul className="py-8">
<Accordion>
{channel.map((c) => (
<Channel
<AccordionItem
key={c.channel_id}
channel={c}
showDetails={c.channel_id === showDetails}
isLoading={isLoading}
onClick={toggleDetailHandler}
onDelete={onDelete}
/>
aria-label={`Channel: ${c.peer_alias}`}
title={c.peer_alias}
>
<Channel channel={c} isLoading={isLoading} onDelete={onDelete} />
</AccordionItem>
))}
</ul>
</Accordion>
);
};

Expand Down
3 changes: 1 addition & 2 deletions src/pages/Home/ListChannelModal/ListChannelModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
ConfirmModal,
type Props as ConfirmModalProps,
} from "@/components/ConfirmModal";
import Message from "@/components/Message";
import { LightningChannel } from "@/models/lightning-channel";
import { checkError } from "@/utils/checkError";
import { instance } from "@/utils/interceptor";
Expand Down Expand Up @@ -84,7 +83,7 @@ export default function ListChannelModal({
isLoading={isLoading}
/>
)}
{error && <Message message={error} />}
{error && <Alert color="danger">{error}</Alert>}
</ConfirmModal.Body>
</ConfirmModal>
);
Expand Down

0 comments on commit c3bf764

Please sign in to comment.