Skip to content

Commit

Permalink
Draft, changing state (#155)
Browse files Browse the repository at this point in the history
* draft, changing state

* component working properly

* .

* method name changed
  • Loading branch information
byAall authored Mar 8, 2024
1 parent af388dd commit 73665f5
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 42 deletions.
4 changes: 2 additions & 2 deletions sample/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ const Application = () => {
<Button size='xs' onClick={setToggle}>
Toggle Data
</Button>
<Button size='xs' onClick={() => setAlert(true)}>Success</Button>
<Button size='xs' onClick={() => setAlert(false)}>Error</Button>
<Button size='xs' onClick={() => setAlert(true, 'Success')}>Success</Button>
<Button size='xs' onClick={() => setAlert(false, 'Error', false)}>Error</Button>
<VirtualSelect
value={virtualSelectOption}
onValueChange={setVirtualSelectOption}
Expand Down
92 changes: 65 additions & 27 deletions src/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import React from 'react';
import React, { ReactNode } from 'react';
import { Checkmark28Regular, Dismiss28Regular } from '@fluentui/react-icons';
import tw from 'tailwind-styled-components';
import useAlertStore from '../useAlertStore';
import { createPortal } from 'react-dom';

const StyledContainer = tw.div`
const AUTO_ANIMATE = ' animate-[slideInTop_4s_ease-out_forwards] ';

const StyledContainer = ({
children,
animation,
ereaseAlert,
}: {
children: ReactNode;
animation: string;
ereaseAlert: () => void;
}) => (
<div
className={`
shadow-alert
font-sans
absolute
top-6
right-7
min-h-[61px]
min-w-[288px]
max-w-[320px]
Expand All @@ -21,40 +30,69 @@ const StyledContainer = tw.div`
items-center
text-lg
invisible
animate-[slideInTop_4s_ease-out_forwards]
${animation}
z-40
[&_svg]:mr-2
[&_svg]:ml-[14px]
[&_svg]:min-w-[28px]
[&>p]:max-w-full
[&>p]:m-0
`;
mb-3
`}
onClick={ereaseAlert}
>
{children}
</div>
);

type AlertProps = {
message?: string;
animation: string;
deleteAlert: () => void;
icon: ReactNode;
};

const AlertSuccess = ({ message = 'Changes Saved Successfully' }: AlertProps) => (
<StyledContainer>
<Checkmark28Regular primaryFill='#1d910c' />
{message}
</StyledContainer>
);

const AlertError = ({ message = 'Something Went Wrong' }: AlertProps) => (
<StyledContainer>
<Dismiss28Regular primaryFill='#e72727' />
{message}
</StyledContainer>
);
const AlertComponent = ({ message, animation, deleteAlert, icon }: AlertProps) => {
if (animation === AUTO_ANIMATE)
setTimeout(() => {
deleteAlert();
}, 4500);
return (
<StyledContainer animation={animation} ereaseAlert={animation === AUTO_ANIMATE ? () => {} : deleteAlert}>
{icon}
{message}
</StyledContainer>
);
};

export const Alert = () => {
const [isSuccess, message] = useAlertStore((state) => [state.isSuccess, state.message]);
const [activeAlerts, deleteAlerts] = useAlertStore((state) => [state.activeAlerts, state.deleteAlerts]);

return (
<>
{isSuccess && <AlertSuccess message={message} />}
{isSuccess === false && <AlertError message={message} />}
</>
const animationElection = (isTimed: boolean): string =>
isTimed ? AUTO_ANIMATE : ' animate-[fadeIn_0.5s_ease-out_forwards] hover:bg-gray-400 ';

return createPortal(
<div className='flex flex-col absolute top-6 right-7 gap-1'>
{activeAlerts.map((alert) => (
<AlertComponent
message={
alert.isSuccess
? alert.message || 'Changes Saved Successfully'
: alert.message || 'Something Went Wrong'
}
animation={animationElection(alert.isTimed)}
key={alert.id}
deleteAlert={() => deleteAlerts(alert.id)}
icon={
alert.isSuccess ? (
<Checkmark28Regular primaryFill='#1d910c' />
) : (
<Dismiss28Regular primaryFill='#e72727' />
)
}
/>
))}
</div>,
document.body,
);
};
31 changes: 31 additions & 0 deletions src/resources/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,37 @@
}
}


.alert-only-fade-in {
@keyframes fadeIn {
0% {
transform: translateY(-40px);
visibility: visible;
opacity: 0;
}
100% {
transform: translateY(0px);
visibility: visible;
opacity: 1;
}
}
}

.alert-only-fade-out {
@keyframes fadeOut {
0% {
transform: translateY(0px);
visibility: visible;
opacity: 1;
}
100% {
transform: translateY(-40px);
visibility: hidden;
opacity: 0;
}
}
}

.animated-menu {
-webkit-animation-duration: 600ms;
animation-duration: 600ms;
Expand Down
35 changes: 22 additions & 13 deletions src/useAlertStore.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { create } from 'zustand';
import { Alert } from './Alert';

interface AlertState {
message?: string;
isSuccess?: boolean;
setAlert: (isSuccess: boolean, message?: string) => void;
interface Alert {
id: number;
message: string;
isSuccess: boolean;
isTimed: boolean;
}

export default create<AlertState>((set) => ({
isSuccess: undefined,
message: undefined,
setAlert: (isSuccess: boolean, message?: string) => {
set(() => {
setTimeout(() => set({ isSuccess, message }), 200);
interface AlertList {
activeAlerts: Alert[];
setAlert: (isSuccess: boolean, message: string, isTimed?: boolean) => void;
deleteAlerts: (alertId: number) => void;
}

return { message: undefined, isSuccess: undefined };
});
},
export default create<AlertList>((set) => ({
activeAlerts: [],
setAlert: (isSuccess: boolean, message: string, isTimed: boolean = true) =>
set((state) => ({
activeAlerts: [
...state.activeAlerts,
{ isSuccess: isSuccess, isTimed: isTimed, message: message, id: Date.now() },
],
})),
deleteAlerts: (alertId: number) =>
set((state) => ({ activeAlerts: state.activeAlerts.filter((alert) => alert.id !== alertId) })),
}));

0 comments on commit 73665f5

Please sign in to comment.