Skip to content

Commit

Permalink
fix: alert that reflect standards
Browse files Browse the repository at this point in the history
  • Loading branch information
atashaikh-MRM committed Mar 8, 2024
1 parent 0bfccdc commit 7ab5d52
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 3 deletions.
6 changes: 3 additions & 3 deletions packages/app/components/pack_table/DeletePackItemModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { MaterialIcons } from '@expo/vector-icons';
import { useDeletePackItem } from 'app/hooks/packs/useDeletePackItem';
import { BaseModal } from '@packrat/ui';
import { BaseAlert } from '@packrat/ui';
import { useDeleteItem } from 'app/hooks/items';

interface DeletePackItemModalProps {
Expand Down Expand Up @@ -46,7 +46,7 @@ export const DeletePackItemModal = ({
];

return (
<BaseModal
<BaseAlert
isOpen={isOpen}
toggle={toggle}
hideIcon={hideIcon}
Expand All @@ -55,6 +55,6 @@ export const DeletePackItemModal = ({
footerButtons={footerButtons}
>
Are you sure you want to delete this item?
</BaseModal>
</BaseAlert>
);
};
64 changes: 64 additions & 0 deletions packages/ui/src/alert/AlertDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useState } from 'react';

import { Adapt, Button, AlertDialog, Sheet } from 'tamagui';

export const Alert = ({ title, description, trigger, children }) => {
const [open, setOpen] = useState(false);

return (
<AlertDialog
modal
onOpenChange={(open) => {
setOpen(open);
}}
>
<AlertDialog.Trigger asChild>
<Button>{trigger}</Button>
</AlertDialog.Trigger>
<Adapt when="sm" platform="touch">
<Sheet zIndex={200000} modal dismissOnSnapToBottom>
<Sheet.Frame padding="$4" gap>
<Adapt.Contents />
</Sheet.Frame>

<Sheet.Overlay
animation="lazy"
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
</Sheet>
</Adapt>
<AlertDialog.Portal>
<AlertDialog.Overlay
key="overlay"
animation="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<AlertDialog.Content
bordered
elevate
key="content"
animateOnly={['transform', 'opacity']}
animation={[
'quick',
{
opacity: {
overshootClamping: true,
},
},
]}
enterStyle={{ x: 0, y: -20, opacity: 0, scale: 0.9 }}
exitStyle={{ x: 0, y: 10, opacity: 0, scale: 0.95 }}
gap
>
<AlertDialog.Title>{title}</AlertDialog.Title>

<AlertDialog.Description>{description}</AlertDialog.Description>
{children}
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog>
);
};
168 changes: 168 additions & 0 deletions packages/ui/src/alert/BaseAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React, { useEffect, useMemo, useState } from 'react';
import { Button, AlertDialog } from 'tamagui';
import { X } from '@tamagui/lucide-icons';
import RButton from '@packrat/ui/src/RButton';
import RStack from '@packrat/ui/src/RStack';
import { useAlert, AlertProvider } from './provider';

export interface BaseAlertProps {
id?: string;
title: string;
trigger?: string;
children: React.ReactNode;
buttonColor?: string;
footerButtons?: any[];
triggerComponent?: React.DetailedReactHTMLElement<any, HTMLElement>;
footerComponent: React.DetailedReactHTMLElement<any, HTMLElement>;
hideIcon?: boolean;
isOpen?: boolean | undefined;
toggle?: any;
}

export const BaseAlert = ({
triggerComponent,
title,
trigger,
footerButtons,
footerComponent,
children,
hideIcon = false,
isOpen = undefined,
toggle,
}: BaseAlertProps) => {
const [isAlertOpen, setIsAlertOpen] = useState(false);

useEffect(() => {
if(isOpen !== undefined) {
setIsAlertOpen(isOpen)
}
}, [isOpen])

const triggerElement = useMemo(() => {
return triggerComponent ? (
<RButton
onPress={() => setIsAlertOpen(true)}
style={{ backgroundColor: 'transparent' }}
backgroundColor={'transparent'}
>
{React.cloneElement(triggerComponent, { setIsAlertOpen })}
</RButton>
) : (
<RButton
top={5}
alignSelf={'center'}
onPress={() => setIsAlertOpen(true)}
>
{trigger}
</RButton>
);
}, [triggerComponent]);

const memoFooterButtons = useMemo(() => {
if (!Array.isArray(footerButtons)) return null;

return footerButtons.map(({ color, label, onClick, ...button }, index) => (
<RButton
key={index}
onPress={withAlertCloseHandler(onClick, () => {
setIsAlertOpen(false)
if(toggle) {
toggle()
}
})}
backgroundColor={color}
disabled={button.disabled}
color="white"
{...button}
>
{label}
</RButton>
));
}, [footerButtons]);

const footerElement = useMemo(() => {
return (
footerComponent && React.cloneElement(footerComponent, { setIsAlertOpen })
);
}, [footerComponent]);

return (
<AlertDialog
modal
open={isAlertOpen}
onOpenChange={(open) => {
setIsAlertOpen(open);
}}
>
{!hideIcon && <AlertDialog.Trigger asChild>{triggerElement}</AlertDialog.Trigger>}
<AlertDialog.Portal>
<AlertDialog.Overlay
key="overlay"
animation="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
minWidth={400}
/>

<AlertDialog.Content
bordered
elevate
key="content"
animateOnly={['transform', 'opacity']}
animation={[
'quick',
{
opacity: {
overshootClamping: true,
},
},
]}
enterStyle={{ x: 0, y: -20, opacity: 0, scale: 0.9 }}
exitStyle={{ x: 0, y: 10, opacity: 0, scale: 0.95 }}
gap="$4"
>
<AlertDialog.Title>{title}</AlertDialog.Title>
<AlertDialog.Description>
<AlertProvider
isAlertOpen={isAlertOpen}
setIsAlertOpen={setIsAlertOpen}
>
{children}
</AlertProvider>
</AlertDialog.Description>

<RStack
style={{ alignSelf: 'flex-end', flexDirection: 'row' }}
gap="$4"
>
{memoFooterButtons}
</RStack>
{footerElement}
<AlertDialog.Cancel asChild>
<Button
onPress={() => {
setIsAlertOpen(false);
if(toggle) {
toggle()
}
}}
position="absolute"
backgroundColor="transparent"
top="$3"
right="$3"
size="$2"
circular
icon={X}
/>
</AlertDialog.Cancel>
</AlertDialog.Content>
</AlertDialog.Portal>
</AlertDialog>
);
};

const withAlertCloseHandler =
(fn, closeHandler) =>
(...args) =>
fn?.(...args, closeHandler.bind(null, false));
2 changes: 2 additions & 0 deletions packages/ui/src/alert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { BaseAlert } from './BaseAlert';
export { useAlert, AlertProvider } from './provider';
26 changes: 26 additions & 0 deletions packages/ui/src/alert/provider/AlertProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createContext, useContext, useState } from 'react';

interface AlertProviderProps {
children?: any;
isAlertOpen: boolean;
setIsAlertOpen: (value: boolean) => void;
}

export const AlertContext = createContext<AlertProviderProps>({
isAlertOpen: false,
setIsAlertOpen: () => {},
});

export const AlertProvider = ({
children,
isAlertOpen,
setIsAlertOpen,
}: AlertProviderProps) => {
const _value = { isAlertOpen, setIsAlertOpen };

return (
<AlertContext.Provider value={_value}>{children}</AlertContext.Provider>
);
};

export const useAlert = () => useContext(AlertContext);
1 change: 1 addition & 0 deletions packages/ui/src/alert/provider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { AlertProvider, useAlert } from './AlertProvider';
1 change: 1 addition & 0 deletions packages/ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export * from './form';
export { config } from './tamagui.config';
// export * from 'tamagui';
export * from './modal';
export * from './alert';
export * from './dialog';
export * from '@tamagui/toast';
export * from './toast';
Expand Down

0 comments on commit 7ab5d52

Please sign in to comment.