Skip to content

Commit

Permalink
feat(connect-kit/x-settings): add operator-detail
Browse files Browse the repository at this point in the history
  • Loading branch information
runjuu committed Mar 10, 2023
1 parent 01159ee commit a3bcc26
Show file tree
Hide file tree
Showing 16 changed files with 469 additions and 40 deletions.
5 changes: 5 additions & 0 deletions packages/connect-kit/src/components/main-btn/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@
color: #fff;
background: #6ad991;
}

.red {
color: #fff;
background: #e65040;
}
1 change: 1 addition & 0 deletions packages/connect-kit/src/components/main-btn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const colorMap = {
yellow: styles.yellow,
gray: styles.gray,
green: styles.green,
red: styles.red,
none: "",
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
.container {
position: relative;
padding: 10px 10px 10px 20px;
padding: 6px 12px;
min-height: 64px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 64px;
gap: 8px;
box-sizing: border-box;
background-color: #f6f6f6;
border-radius: 12px;
}

.container:not(:last-child)::after {
position: absolute;
content: "";
bottom: 0;
left: 52px;
right: 0;
height: 1px;
background: #e1e8f7;
.main {
flex: 1;
width: 0;
}

.title {
color: #49454f;
font-weight: 500;
font-size: 16px;
display: flex;
align-items: center;
gap: 6px;
}

.description {
color: #999;
font-weight: 500;
font-size: 12px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}

.tags {
Expand All @@ -40,7 +44,7 @@

.tags span {
font-size: 11px;
padding: 0 9px;
padding: 0 6px;
border-radius: 4px;
background: white;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import React from "react";
import classNames from "classnames";
import { CharacterOperatorEntity } from "crossbell.js";
import { Loading } from "@crossbell/ui";
import { truncateAddress } from "@crossbell/util-ethers";
import { CharacterAvatar, Loading, useWeb2Url } from "@crossbell/ui";
import { isAddressEqual, truncateAddress } from "@crossbell/util-ethers";
import { useRefCallback } from "@crossbell/util-hooks";
import { RemoveOperator } from "../remove-operator";
import { usePrimaryCharacter } from "@crossbell/indexer";

import commonStyles from "../../../styles.module.css";
import { useCharacterOperatorPermissions } from "../../../hooks";
import {
OP_SIGN_OPERATOR_ADDRESS,
useCharacterOperatorPermissions,
X_SYNC_OPERATOR_ADDRESS,
} from "../../../hooks";
import { useDynamicScenesModal } from "../../../components";

import { OperatorDetail } from "../operator-detail";
import { RemoveOperator } from "../remove-operator";

import styles from "./item.module.css";

export type ItemTag = {
Expand Down Expand Up @@ -37,7 +44,9 @@ export function Item({
const permissions = data ?? [];

const { goTo, goBack } = useDynamicScenesModal();
const goToRemoveOperator = useRefCallback(() => {

const goToRemoveOperator = useRefCallback((event: React.MouseEvent) => {
event.stopPropagation();
goTo({
kind: "remove-operator",
Component: () => (
Expand All @@ -50,22 +59,51 @@ export function Item({
});
});

const goToOperatorDetail = useRefCallback(() => {
goTo({
kind: "remove-operator",
Component: () => (
<OperatorDetail
characterOperator={characterOperator}
description={description}
characterId={characterId}
tags={tags}
/>
),
});
});

const { data: primaryCharacter } = usePrimaryCharacter(
characterOperator.operator
);

const handle = primaryCharacter?.handle ? `@${primaryCharacter.handle}` : "";
const avatar = useOperatorAvatar(characterOperator);

return (
<div className={styles.container}>
<div>
<div
className={classNames(styles.container, commonStyles.uxOverlay)}
onClick={goToOperatorDetail}
>
<CharacterAvatar size="32px" character={primaryCharacter} src={avatar} />

<div className={styles.main}>
<div title={characterOperator.operator} className={styles.title}>
{truncateAddress(characterOperator.operator, { start: 8, end: 9 })}
<span>
{truncateAddress(characterOperator.operator, { start: 4, end: 4 })}
</span>

{tags && tags.length > 0 && (
<div className={styles.tags}>
{tags.map((tag) => (
<span key={tag.title} style={tag.style}>
{tag.title}
</span>
))}
</div>
)}
</div>
<div className={styles.description}>{description}</div>
{tags && tags.length > 0 && (
<div className={styles.tags}>
{tags.map((tag) => (
<span key={tag.title} style={tag.style}>
{tag.title}
</span>
))}
</div>
)}
<div className={styles.description}>{description ?? handle}</div>
</div>

{isLoading ? (
Expand All @@ -83,3 +121,20 @@ export function Item({
</div>
);
}

export function useOperatorAvatar(
characterOperator: CharacterOperatorEntity
): string | undefined {
const administratorUrl = useWeb2Url(
"ipfs://bafkreibqpox3lhci37urb6vrcleicaedscqwlyeuqxawtkfc5vavldtziy"
);

if (
isAddressEqual(characterOperator.operator, X_SYNC_OPERATOR_ADDRESS) ||
isAddressEqual(characterOperator.operator, OP_SIGN_OPERATOR_ADDRESS)
) {
return administratorUrl;
}

return undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
.list {
margin: 10px 24px 24px;
border-radius: 12px;
background: #f6f6f6;
display: flex;
flex-direction: column;
gap: 12px;
}

.itemTitle {
Expand All @@ -19,3 +21,8 @@
height: 150px;
opacity: 0.8;
}

.loading {
font-size: 32px;
opacity: 0.8;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { ScrollArea } from "@mantine/core";
import { LoadMore, LoadingOverlay } from "@crossbell/ui";
import { LoadMore, Loading } from "@crossbell/ui";
import { isAddressEqual } from "@crossbell/util-ethers";
import { CharacterOperatorEntity } from "crossbell.js";

Expand Down Expand Up @@ -30,27 +30,31 @@ export function List({ characterId }: ListProps) {
page.list.map((characterOperator) => ({
characterOperator: characterOperator,
tags: getTags(characterOperator),
description: getDescription(characterOperator),
}))
)
.sort((a, b) => (a.tags ? (b.tags ? 0 : -1) : 1)) ?? [],
.filter(
({ characterOperator }) => characterOperator.permissions.length > 0
)
.sort((a, b) => (a.description ? (b.description ? 0 : -1) : 1)) ?? [],
[data]
);

return (
<ScrollArea.Autosize mah="70vh" className={styles.container}>
<LoadingOverlay visible={isLoading && isFetchingNextPage} />

{list.length === 0 && (
<div className={styles.emptyTips}>No operators</div>
<div className={styles.emptyTips}>
{isLoading ? <Loading className={styles.loading} /> : "No operators"}
</div>
)}

<div className={styles.list}>
{list.map(({ characterOperator, tags }) => (
{list.map(({ characterOperator, tags, description }) => (
<Item
key={characterOperator.operator}
characterId={characterId}
characterOperator={characterOperator}
description={getDescription(characterOperator)}
description={description}
tags={tags}
/>
))}
Expand Down Expand Up @@ -78,7 +82,9 @@ function getTags(characterOperator: CharacterOperatorEntity): ItemTag[] | null {
];
}

return null;
return [
{ title: "Unknown", style: { background: "#A9AAAB", color: "#fff" } },
];
}

function getDescription(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.mainBtn {
margin-top: 48px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from "react";
import { useRefCallback } from "@crossbell/util-hooks";
import { truncateAddress } from "@crossbell/util-ethers";

import {
DynamicScenesContainer,
DynamicScenesHeader,
MainBtn,
useDynamicScenesModal,
} from "../../../components";

import { OperatorCard } from "./operator-card";
import { RemoveOperator } from "../remove-operator";

import styles from "./index.module.css";
import { PermissionList } from "./permission-list";

export type OperatorDetailProps = React.ComponentProps<typeof OperatorCard>;

export function OperatorDetail({
characterOperator,
description,
characterId,
tags,
}: OperatorDetailProps) {
const { goTo, goBack } = useDynamicScenesModal();

const goToRemoveOperator = useRefCallback((event: React.MouseEvent) => {
event.stopPropagation();
goTo({
kind: "remove-operator",
Component: () => (
<RemoveOperator
characterOperator={characterOperator}
onSuccess={() => {
goBack();
goBack();
}}
onCancel={goBack}
/>
),
});
});
return (
<DynamicScenesContainer
padding="10px 24px 24px"
header={
<DynamicScenesHeader
title={truncateAddress(characterOperator.operator, {
start: 4,
end: 4,
})}
/>
}
>
<OperatorCard
tags={tags}
characterOperator={characterOperator}
description={description}
characterId={characterId}
/>

<PermissionList
characterId={characterId}
characterOperator={characterOperator}
/>

<MainBtn
onClick={goToRemoveOperator}
color="red"
className={styles.mainBtn}
>
Remove Operator
</MainBtn>
</DynamicScenesContainer>
);
}

0 comments on commit a3bcc26

Please sign in to comment.