Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add logout #206

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions pkgs/frontend/app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import { useState, useEffect, useMemo } from "react";
import { Box, Flex, Text } from "@chakra-ui/react";
import { WorkspaceIcon } from "./icon/WorkspaceIcon";
import { UserIcon } from "./icon/UserIcon";
import { useLocation } from "@remix-run/react";
import { useLocation, useNavigate } from "@remix-run/react";
import { useActiveWalletIdentity } from "hooks/useENS";
import { ipfs2https } from "utils/ipfs";
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from "./ui/menu";
import { useActiveWallet } from "hooks/useWallet";
import { usePrivy, useWallets } from "@privy-io/react-auth";
import CommonButton from "./common/CommonButton";

const NO_HEADER_PATHS: string[] = ["/login", "/signup"]; // 適宜ヘッダーが不要なページのパスを追加
const WORKSPACES_PATHS: string[] = ["/workspaces"]; // 適宜ワークスペースが未選択な状態のページのパスを追加
Expand All @@ -28,6 +32,7 @@ export const Header = () => {
HeaderType.NonHeader
);

const navigate = useNavigate();
const { pathname } = useLocation();

// ToDo: ページのパスや hooks で柔軟にロジックを実装する(切り替えてテストできます)
Expand Down Expand Up @@ -63,13 +68,28 @@ export const Header = () => {
workspaceName,
]);

const { isSmartWallet } = useActiveWallet();
const { logout } = usePrivy();
const { wallets } = useWallets();
const { identity } = useActiveWalletIdentity();

const userImageUrl = useMemo(() => {
const avatar = identity?.text_records?.["avatar"];
return avatar ? ipfs2https(avatar) : undefined;
}, [identity]);

const handleLogout = () => {
if (isSmartWallet) {
logout();
} else {
if (wallets.find((w) => w.connectorType === "injected")) {
alert("ウォレット拡張機能から切断してください。");
} else {
Promise.all(wallets.map((wallet) => wallet.disconnect()));
}
}
};

return headerType !== HeaderType.NonHeader ? (
<Flex justifyContent="space-between" w="100%">
<Box display="flex" height={HEADER_SIZE} flex="1">
Expand All @@ -90,7 +110,29 @@ export const Header = () => {
</>
)}
</Box>
<UserIcon userImageUrl={userImageUrl} size={HEADER_SIZE - 2} />
{identity ? (
<MenuRoot closeOnSelect={false}>
<MenuTrigger asChild>
<button>
<UserIcon userImageUrl={userImageUrl} size={HEADER_SIZE - 2} />
</button>
</MenuTrigger>
<MenuContent>
<MenuItem value="logout" onClick={handleLogout}>
Logout
</MenuItem>
</MenuContent>
</MenuRoot>
) : (
<CommonButton
onClick={() => {
navigate("/login");
}}
w="auto"
>
Login
</CommonButton>
)}
</Flex>
) : (
<></>
Expand Down
110 changes: 110 additions & 0 deletions pkgs/frontend/app/components/ui/menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use client"

import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react"
import * as React from "react"
import { LuCheck, LuChevronRight } from "react-icons/lu"

interface MenuContentProps extends ChakraMenu.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}

export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner>
</Portal>
)
},
)

export const MenuArrow = React.forwardRef<
HTMLDivElement,
ChakraMenu.ArrowProps
>(function MenuArrow(props, ref) {
return (
<ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip />
</ChakraMenu.Arrow>
)
})

export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.CheckboxItemProps
>(function MenuCheckboxItem(props, ref) {
return (
<ChakraMenu.CheckboxItem ref={ref} {...props}>
<ChakraMenu.ItemIndicator hidden={false}>
<LuCheck />
</ChakraMenu.ItemIndicator>
{props.children}
</ChakraMenu.CheckboxItem>
)
})

export const MenuRadioItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) {
const { children, ...rest } = props
return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild>
<ChakraMenu.ItemIndicator>
<LuCheck />
</ChakraMenu.ItemIndicator>
</AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem>
)
})

export const MenuItemGroup = React.forwardRef<
HTMLDivElement,
ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props
return (
<ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && (
<ChakraMenu.ItemGroupLabel userSelect="none">
{title}
</ChakraMenu.ItemGroupLabel>
)}
{children}
</ChakraMenu.ItemGroup>
)
})

export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
startIcon?: React.ReactNode
}

export const MenuTriggerItem = React.forwardRef<
HTMLDivElement,
MenuTriggerItemProps
>(function MenuTriggerItem(props, ref) {
const { startIcon, children, ...rest } = props
return (
<ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon}
{children}
<LuChevronRight />
</ChakraMenu.TriggerItem>
)
})

export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup
export const MenuContextTrigger = ChakraMenu.ContextTrigger
export const MenuRoot = ChakraMenu.Root
export const MenuSeparator = ChakraMenu.Separator

export const MenuItem = ChakraMenu.Item
export const MenuItemText = ChakraMenu.ItemText
export const MenuItemCommand = ChakraMenu.ItemCommand
export const MenuTrigger = ChakraMenu.Trigger
5 changes: 4 additions & 1 deletion pkgs/frontend/hooks/useWallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useWallets } from "@privy-io/react-auth";
import { usePrivy, useWallets } from "@privy-io/react-auth";
import { createSmartAccountClient, SmartAccountClient } from "permissionless";
import { toSimpleSmartAccount } from "permissionless/accounts";
import { createPimlicoClient } from "permissionless/clients/pimlico";
Expand Down Expand Up @@ -36,6 +36,8 @@ export const useSmartAccountClient = () => {
* @returns
*/
const create = async () => {
setClient(undefined);
console.log(wallets);
const embeddedWallet = wallets.find(
(wallet) => wallet.connectorType === "embedded"
);
Expand Down Expand Up @@ -78,6 +80,7 @@ export const useAccountClient = () => {

useEffect(() => {
const create = async () => {
setClient(undefined);
if (!wallets[0]) return;
const wallet = wallets[0];

Expand Down
4 changes: 2 additions & 2 deletions pkgs/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json}\""
},
"dependencies": {
"@chakra-ui/react": "^3.2.0",
"@chakra-ui/react": "^3.2.3",
"@emotion/cache": "^11.13.5",
"@emotion/react": "^11.13.5",
"@emotion/server": "^11.11.0",
Expand All @@ -33,7 +33,7 @@
"permissionless": "^0.2.20",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"react-icons": "^5.4.0",
"viem": "^2.21.51"
},
"devDependencies": {
Expand Down
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1308,10 +1308,10 @@
dependencies:
"@chainsafe/is-ip" "^2.0.1"

"@chakra-ui/react@^3.2.0":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-3.2.2.tgz#cd846cdfaf9002d7339f15e1932ed2a886c7374b"
integrity sha512-9GAESg6rSJ4NCfPAv2s5mOYnrFU+5x3xxR9Ab1phsZ2junR7po55PxB/Zdr1VNb1NX+6oIGMAR5s74oN5sYlfQ==
"@chakra-ui/react@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-3.2.3.tgz#61615fbee75e9aedb6bb136d15de5ce99184f9da"
integrity sha512-KfhKkcnHPqMwrX5eZ1xVeewOy6L4+iL2684tnP7re7erferfEBeqAAkGZpzWUcjb+IMwClYFygXk0gQrsVdtaQ==
dependencies:
"@ark-ui/react" "4.4.4"
"@emotion/is-prop-valid" "1.3.1"
Expand Down Expand Up @@ -15524,10 +15524,10 @@ react-helmet-async@^1.3.0:
react-fast-compare "^3.2.0"
shallowequal "^1.1.0"

react-icons@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.3.0.tgz#ccad07a30aebd40a89f8cfa7d82e466019203f1c"
integrity sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==
react-icons@^5.4.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.4.0.tgz#443000f6e5123ee1b21ea8c0a716f6e7797f7416"
integrity sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==

react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1"
Expand Down
Loading