diff --git a/apps/app/src/app/pages/chatbox/library.tsx b/apps/app/src/app/pages/chatbox/library.tsx
index 0e7d3ed..8af8e63 100644
--- a/apps/app/src/app/pages/chatbox/library.tsx
+++ b/apps/app/src/app/pages/chatbox/library.tsx
@@ -1,15 +1,8 @@
-import { useDeleteChatTheme, useUserChatThemes } from '@streali/shared/hooks';
-import {
- Button,
- ButtonColor,
- Popover,
- PopoverNavigation,
-} from '@streali/shared/ui';
-import { toastr, ToastType } from '@streali/shared/utils';
+import { useUserChatThemes } from '@streali/shared/hooks';
+import { Button, ChatCard } from '@streali/shared/ui';
export function LibraryChatbox() {
const { data, isLoading } = useUserChatThemes();
- const { mutate: deleteChatTheme } = useDeleteChatTheme();
return (
@@ -24,60 +17,8 @@ export function LibraryChatbox() {
{data &&
data.length > 0 &&
data?.map((theme) => (
-
-
{theme.title}
-
- }
- >
-
{
- navigator.clipboard.writeText(
- `${window.location.origin.toString()}/chatbox/${
- theme.id
- }/embed`
- );
- toastr(
- ToastType.Success,
- 'Embed link copied',
- 'You can use this link on your streaming software'
- );
- },
- icon: 'file-copy-line',
- },
- {
- title: 'Delete',
- icon: 'delete-bin-line',
- color: 'error',
- confirm: {
- title: 'Delete chatbox',
- text: 'Are you sure you want to delete this chatbox theme?',
- word: theme.title,
- confirmText:
- 'For delete this chatbox theme, type the name of the chatbox theme',
- textButton: 'Delete',
- onConfirm: () => {
- theme.id && deleteChatTheme(theme.id);
- },
- },
- },
- ]}
- />
-
+
+
))}
diff --git a/apps/app/src/main.tsx b/apps/app/src/main.tsx
index 70fd8bc..9b3f879 100644
--- a/apps/app/src/main.tsx
+++ b/apps/app/src/main.tsx
@@ -30,7 +30,7 @@ const root = ReactDOM.createRoot(
root.render(
-
+
diff --git a/libs/shared/ui/src/index.ts b/libs/shared/ui/src/index.ts
index 075b03e..0fc80af 100644
--- a/libs/shared/ui/src/index.ts
+++ b/libs/shared/ui/src/index.ts
@@ -1,3 +1,4 @@
+export * from './lib/components/chat-card/chat-card';
export * from './lib/components/confirmation/confirmation';
export * from './lib/components/code-editor/code-editor';
export * from './lib/components/popover-navigation/popover-navigation';
diff --git a/libs/shared/ui/src/lib/components/chat-card/chat-card.spec.tsx b/libs/shared/ui/src/lib/components/chat-card/chat-card.spec.tsx
new file mode 100644
index 0000000..130e8ed
--- /dev/null
+++ b/libs/shared/ui/src/lib/components/chat-card/chat-card.spec.tsx
@@ -0,0 +1,10 @@
+import { render } from '@testing-library/react';
+
+import ChatCard from './chat-card';
+
+describe('ChatCard', () => {
+ it('should render successfully', () => {
+ const { baseElement } = render();
+ expect(baseElement).toBeTruthy();
+ });
+});
diff --git a/libs/shared/ui/src/lib/components/chat-card/chat-card.tsx b/libs/shared/ui/src/lib/components/chat-card/chat-card.tsx
new file mode 100644
index 0000000..b056de1
--- /dev/null
+++ b/libs/shared/ui/src/lib/components/chat-card/chat-card.tsx
@@ -0,0 +1,73 @@
+import { toastr, ToastType } from '@streali/shared/utils';
+import Button, { ButtonColor } from '../button/button';
+import PopoverNavigation from '../popover-navigation/popover-navigation';
+import Popover from '../popover/popover';
+import { useDeleteChatTheme } from '@streali/shared/hooks';
+import { useState } from 'react';
+
+export interface ChatCardProps {
+ title: string;
+ id: string;
+}
+
+export function ChatCard(props: ChatCardProps) {
+ const { title, id } = props;
+ const { mutate: deleteChatTheme } = useDeleteChatTheme();
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ return (
+
+
{title}
+
}
+ >
+
setMenuOpen(false)}
+ links={[
+ {
+ title: 'Edit',
+ link: `/chatbox/${id}/edit`,
+ icon: 'edit-box-line',
+ },
+ {
+ title: 'Embed',
+ onClick: () => {
+ navigator.clipboard.writeText(
+ `${window.location.origin.toString()}/chatbox/${id}/embed`
+ );
+ toastr(
+ ToastType.Success,
+ 'Embed link copied',
+ 'You can use this link on your streaming software'
+ );
+ },
+ icon: 'file-copy-line',
+ },
+ {
+ title: 'Delete',
+ icon: 'delete-bin-line',
+ color: 'error',
+ confirm: {
+ title: 'Delete chatbox',
+ text: 'Are you sure you want to delete this chatbox theme?',
+ word: title,
+ confirmText:
+ 'For delete this chatbox theme, type the name of the chatbox theme',
+ textButton: 'Delete',
+ onConfirm: () => {
+ id && deleteChatTheme(id);
+ },
+ },
+ },
+ ]}
+ />
+
+
+ );
+}
+
+export default ChatCard;
diff --git a/libs/shared/ui/src/lib/components/confirmation/confirmation.tsx b/libs/shared/ui/src/lib/components/confirmation/confirmation.tsx
index 153b114..8b7b42c 100644
--- a/libs/shared/ui/src/lib/components/confirmation/confirmation.tsx
+++ b/libs/shared/ui/src/lib/components/confirmation/confirmation.tsx
@@ -11,6 +11,7 @@ export interface ConfirmationProps {
confirmText: string;
textButton?: string;
onConfirm?: () => void;
+ onConfirmationClose?: () => void;
}
export function Confirmation(props: ConfirmationProps) {
@@ -22,6 +23,7 @@ export function Confirmation(props: ConfirmationProps) {
confirmText,
textButton = 'Confirm',
onConfirm,
+ onConfirmationClose,
} = props;
const [confirm, setConfirm] = useState('');
const [isOpen, setIsOpen] = useState(false);
@@ -44,6 +46,7 @@ export function Confirmation(props: ConfirmationProps) {
open={isOpen}
onOpenChange={(open) => {
setIsOpen(open);
+ if (!open) onConfirmationClose && onConfirmationClose();
}}
>
{text}
diff --git a/libs/shared/ui/src/lib/components/navigation/nav-vertical/button-nav.tsx b/libs/shared/ui/src/lib/components/navigation/nav-vertical/button-nav.tsx
new file mode 100644
index 0000000..681b678
--- /dev/null
+++ b/libs/shared/ui/src/lib/components/navigation/nav-vertical/button-nav.tsx
@@ -0,0 +1,39 @@
+import { useState } from 'react';
+import Icon from '../../icon/icon';
+import PopoverNavigation, {
+ PopoverLink,
+} from '../../popover-navigation/popover-navigation';
+import Popover from '../../popover/popover';
+
+export interface ButtonNavProps {
+ icon: string;
+ items: PopoverLink[];
+}
+
+function ButtonNav(props: ButtonNavProps) {
+ const { icon, items } = props;
+ const [navOpen, setNavOpen] = useState(false);
+
+ return (
+
+
+
+ }
+ >
+
+
setNavOpen(false)}
+ />
+
+
+ );
+}
+
+export default ButtonNav;
diff --git a/libs/shared/ui/src/lib/components/navigation/nav-vertical/nav-vertical.tsx b/libs/shared/ui/src/lib/components/navigation/nav-vertical/nav-vertical.tsx
index ec57397..62ae64e 100644
--- a/libs/shared/ui/src/lib/components/navigation/nav-vertical/nav-vertical.tsx
+++ b/libs/shared/ui/src/lib/components/navigation/nav-vertical/nav-vertical.tsx
@@ -4,7 +4,9 @@ import PopoverNavigation, {
PopoverLink,
} from '../../popover-navigation/popover-navigation';
import Popover from '../../popover/popover';
-import { useAuthUser, useLogout } from "@streali/shared/hooks";
+import { useAuthUser, useLogout } from '@streali/shared/hooks';
+import ButtonNav from './button-nav';
+import { useState } from 'react';
export interface NavVerticalItems {
icon: string;
@@ -20,6 +22,7 @@ export function NavVertical(props: NavVerticalProps) {
const { data: user } = useAuthUser();
const { mutate: logout } = useLogout();
const { navigation } = props;
+ const [userNavOpen, setUserNavOpen] = useState(false);
const userNavigation: PopoverLink[] = [
{
@@ -43,19 +46,7 @@ export function NavVertical(props: NavVerticalProps) {
{navigation.map((item, index) => (
- }
- >
-
-
+
))}
@@ -63,6 +54,8 @@ export function NavVertical(props: NavVerticalProps) {
{user && (
-
+ setUserNavOpen(false)}
+ />
)}
diff --git a/libs/shared/ui/src/lib/components/popover-navigation/popover-navigation.tsx b/libs/shared/ui/src/lib/components/popover-navigation/popover-navigation.tsx
index 08a9b4f..0241989 100644
--- a/libs/shared/ui/src/lib/components/popover-navigation/popover-navigation.tsx
+++ b/libs/shared/ui/src/lib/components/popover-navigation/popover-navigation.tsx
@@ -21,10 +21,11 @@ export interface PopoverLink {
export interface PopoverNavigationProps {
links: PopoverLink[];
+ onLinkClick?: () => void;
}
export function PopoverNavigation(props: PopoverNavigationProps) {
- const { links } = props;
+ const { links, onLinkClick } = props;
const colorClassName = {
primary: 'hover:bg-primary-500',
@@ -39,6 +40,7 @@ export function PopoverNavigation(props: PopoverNavigationProps) {
{!link.onClick && link.link && (
{
+ link.onClick && link.onClick(e);
+ onLinkClick && onLinkClick();
+ }}
>
{link.icon && }
{link.title}
@@ -65,13 +70,21 @@ export function PopoverNavigation(props: PopoverNavigationProps) {
word={link.confirm.word}
confirmText={link.confirm.confirmText}
textButton={link.confirm.textButton}
- onConfirm={link.confirm.onConfirm}
+ onConfirmationClose={onLinkClick}
+ onConfirm={() => {
+ link.confirm &&
+ link.confirm.onConfirm &&
+ link.confirm.onConfirm();
+ onLinkClick && onLinkClick();
+ }}
trigger={
{
+ link.onClick && link.onClick(e);
+ }}
>
{link.icon &&
}
{link.title}
diff --git a/libs/shared/ui/src/lib/components/popover/popover.tsx b/libs/shared/ui/src/lib/components/popover/popover.tsx
index d5baf05..4171d98 100644
--- a/libs/shared/ui/src/lib/components/popover/popover.tsx
+++ b/libs/shared/ui/src/lib/components/popover/popover.tsx
@@ -1,14 +1,26 @@
import * as PopoverLib from '@radix-ui/react-popover';
+import { useEffect, useState } from 'react';
export interface PopoverProps {
trigger: React.ReactNode;
align?: 'start' | 'center' | 'end';
side?: 'top' | 'right' | 'bottom' | 'left';
children: React.ReactNode;
+ open: boolean;
+ onOpenChange?: (open: boolean) => void;
}
export function Popover(props: PopoverProps) {
- const { trigger, align = 'center', side = 'bottom', children } = props;
+ const {
+ trigger,
+ align = 'center',
+ side = 'bottom',
+ children,
+ open = false,
+ onOpenChange,
+ } = props;
+
+ const [isOpen, setIsOpen] = useState(false);
const animationClassName = {
top: 'slide-down-fade',
@@ -17,8 +29,12 @@ export function Popover(props: PopoverProps) {
left: 'slide-right-fade',
};
+ useEffect(() => {
+ setIsOpen(open);
+ }, [open]);
+
return (
-
+
{trigger}