Skip to content

Commit

Permalink
Show messages in one section
Browse files Browse the repository at this point in the history
  • Loading branch information
JunichiSugiura committed Dec 20, 2024
1 parent 1ae107d commit 7285b0a
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 140 deletions.
33 changes: 0 additions & 33 deletions packages/keychain/src/components/session/CollapsibleRow.tsx

This file was deleted.

48 changes: 15 additions & 33 deletions packages/keychain/src/components/session/ContractCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,7 @@ import {
AccordionTrigger,
} from "@cartridge/ui-next";
import { formatAddress } from "@cartridge/utils";
import {
Divider,
HStack,
Link,
Spacer,
Stack,
Text,
VStack,
} from "@chakra-ui/react";
import { Divider, HStack, Spacer, Stack, Text, VStack } from "@chakra-ui/react";
import { useExplorer } from "@starknet-react/core";
import { constants } from "starknet";
import { Method } from "@cartridge/presets";
Expand All @@ -42,49 +34,39 @@ export function ContractCard({
return (
<Card>
<CardHeader icon={icon}>
<HStack py={4}>
<Text
color="text.primary"
fontSize="xs"
fontWeight="bold"
textTransform="uppercase"
>
{title}
</Text>
<Spacer />
<Link
color="text.secondary"
fontSize="xs"
<div className="flex items-center justify-between">
<div className="text-xs font-bold uppercase">{title}</div>
<a
className="text-xs text-muted-foreground cursor-pointer hover:underline"
href={
chainId === constants.StarknetChainId.SN_MAIN ||
chainId === constants.StarknetChainId.SN_SEPOLIA
? explorer.contract(address)
: `#`
}
target="_blank"
rel="noreferrer"
>
{formatAddress(address, { first: 5, last: 5 })}
</Link>
</HStack>
</a>
</div>
</CardHeader>

<CardContent>
<Accordion type="multiple" defaultValue={["methods"]}>
<AccordionItem value="methods">
<AccordionTrigger>
<Text color="text.secondary" fontSize="xs">
Approve{" "}
<Text as="span" color="text.secondaryAccent" fontWeight="bold">
{methods.length} {methods.length > 1 ? "methods" : "method"}
</Text>
</Text>
<AccordionItem value="methods" className="flex flex-col gap-3">
<AccordionTrigger className="text-xs text-muted-foreground">
Approve{" "}
<span className="text-accent-foreground font-bold">
{methods.length} {methods.length > 1 ? "methods" : "method"}
</span>
</AccordionTrigger>
<AccordionContent>
<Stack
border="1px solid"
spacing={0}
borderColor="darkGray.800"
borderRadius="md"
mt="14px"
divider={<Divider borderColor="solid.bg" />}
>
{methods.map((method) => (
Expand Down
177 changes: 106 additions & 71 deletions packages/keychain/src/components/session/MessageCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { PropsWithChildren, useState } from "react";
import {
Card,
CardContent,
Expand All @@ -10,67 +10,17 @@ import {
CardIcon,
PencilIcon,
AccordionTrigger,
CheckboxIcon,
} from "@cartridge/ui-next";
import { ArrowTurnDownIcon, Badge } from "@cartridge/ui-next";
import { StarknetEnumType, StarknetMerkleType } from "@starknet-io/types-js";
import { SignMessagePolicy } from "@cartridge/presets";
import { Text } from "@chakra-ui/react";

import { CollapsibleRow } from "./CollapsibleRow";

interface MessageContentProps {
message: SignMessagePolicy;
}

function MessageContent({ message: m }: MessageContentProps) {
return (
<CardContent className="text-muted-foreground flex flex-col">
{/* Domain section */}
{Object.values(m.domain).filter((f) => typeof f !== "undefined").length >
0 && (
<CollapsibleRow key="domain" title="domain">
{m.domain.name && (
<ValueRow values={[{ name: "name", value: m.domain.name }]} />
)}
{/* ... other domain fields ... */}
</CollapsibleRow>
)}

<ValueRow values={[{ name: "primaryType", value: m.primaryType }]} />

<CollapsibleRow title="types">
{Object.entries(m.types).map(([name, types]) => (
<CollapsibleRow key={name} title={name}>
{types.map((t) => (
<ValueRow
key={t.name}
values={[
{ name: "name", value: t.name },
{ name: "type", value: t.type },
...(["enum", "merkletree"].includes(t.name)
? [
{
name: "contains",
value: (t as StarknetEnumType | StarknetMerkleType)
.contains,
},
]
: []),
]}
/>
))}
</CollapsibleRow>
))}
</CollapsibleRow>
</CardContent>
);
}

interface MessageCardProps {
message: SignMessagePolicy;
messages: SignMessagePolicy[];
}

export function MessageCard({ message }: MessageCardProps) {
export function MessageCard({ messages }: MessageCardProps) {
return (
<Card>
<CardHeader
Expand All @@ -83,33 +33,118 @@ export function MessageCard({ message }: MessageCardProps) {
<CardTitle className="text-foreground">Sign Message</CardTitle>
</CardHeader>

<Accordion type="single" defaultValue="message" collapsible>
<AccordionItem value="message">
<CardContent>
<AccordionTrigger>
<Text color="text.secondary" fontSize="xs">
The application will be able to sign the following message on
your behalf
</Text>
</AccordionTrigger>
</CardContent>

<AccordionContent>
<MessageContent message={message} />
</AccordionContent>
</AccordionItem>
</Accordion>
<CardContent>
<MessageContent messages={messages} />
</CardContent>
</Card>
);
}

interface MessageContentProps {
messages: SignMessagePolicy[];
}

function MessageContent({ messages }: MessageContentProps) {
return (
<Accordion type="single" defaultValue="message" collapsible>
<AccordionItem value="message" className="flex flex-col gap-3">
<AccordionTrigger
className="text-xs text-muted-foreground"
color="text.secondary"
>
Approve{" "}
<span className="text-accent-foreground font-bold">
{messages.length} {messages.length > 1 ? "message" : "messages"}
</span>
</AccordionTrigger>

<AccordionContent className="text-xs">
{messages.map((m) => (
<>
{/* Domain section */}
{Object.values(m.domain).filter((f) => typeof f !== "undefined")
.length > 0 && (
<CollapsibleRow key="domain" title="domain">
{m.domain.name && (
<ValueRow
values={[{ name: "name", value: m.domain.name }]}
/>
)}
{/* ... other domain fields ... */}
</CollapsibleRow>
)}

<ValueRow
values={[{ name: "primaryType", value: m.primaryType }]}
/>

<CollapsibleRow title="types">
{Object.entries(m.types).map(([name, types]) => (
<CollapsibleRow key={name} title={name}>
{types.map((t) => (
<ValueRow
key={t.name}
values={[
{ name: "name", value: t.name },
{ name: "type", value: t.type },
...(["enum", "merkletree"].includes(t.name)
? [
{
name: "contains",
value: (
t as StarknetEnumType | StarknetMerkleType
).contains,
},
]
: []),
]}
/>
))}
</CollapsibleRow>
))}
</CollapsibleRow>
</>
))}
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
interface CollapsibleRowProps extends PropsWithChildren {
title: string;
}

export function CollapsibleRow({ title, children }: CollapsibleRowProps) {
const [value, setValue] = useState("");

return (
<Accordion type="single" collapsible value={value} onValueChange={setValue}>
<AccordionItem value={title} className="flex flex-col">
<AccordionTrigger hideIcon className="hover:bg-accent rounded-md">
<div className="flex items-center gap-1 py-1">
<CheckboxIcon
variant={value ? "minus-line" : "plus-line"}
size="sm"
/>
<div>{title}</div>
</div>
</AccordionTrigger>

<AccordionContent className="ml-5 flex flex-col">
{children}
</AccordionContent>
</AccordionItem>
</Accordion>
);
}

interface ValueRowProps {
values: { name: string; value: string | number }[];
}

export function ValueRow({ values }: ValueRowProps) {
return (
<div className="flex items-center py-2">
<div className="flex items-center py-1">
<ArrowTurnDownIcon />
<div className="flex items-center gap-2">
{values.map((f) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export function UnverifiedSessionSummary({
);
})}

{policies.messages?.map((message, index) => (
<MessageCard key={index} message={message} />
))}
{policies.messages?.length && (
<MessageCard messages={policies.messages} />
)}
</div>
);
}

0 comments on commit 7285b0a

Please sign in to comment.