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}