added modal click outside to close, consolidated modal context into modal provider

This commit is contained in:
Victor committed 2024-07-30 13:51:12 -07:00
1 parent 8e853e919f
commit bba2b801d7
12 files changed
+156 -162

No files matched your search

@@ -6,80 +6,134 @@ import useLogin from "./useLogin";
import useSignup from "./useSignup";
import LoginView from "./LoginView";
import SignupView from "./SignupView";
import { ModalView } from "context/AccountModalContext";
import { Analytics } from "common/Analytics";
import "./AccountModal.scss";
interface AniProps {
animating: boolean,
isLeaving: boolean,
render: any,
style: any
animating: boolean;
isLeaving: boolean;
render: any;
style: any;
}
const AniMod = ({ animating, isLeaving, render: Render, style, ...rest }: AniProps) => <a.div {...{ style: {
...style,
position: isLeaving && animating ? "absolute" : "relative"
} }}>
export enum AccountModalView {
Closed,
Signup,
Login,
}
const AniMod = ({
animating,
isLeaving,
render: Render,
style,
...rest
}: AniProps) => (
<a.div
{...{
style: {
...style,
position: isLeaving && animating ? "absolute" : "relative",
},
}}
>
<Render {...{ ...rest, animating }} />
</a.div>;
</a.div>
);
const Loader = ({ viewLogin }: { viewLogin: boolean }) => <div {...{ className: `fy-modal-page modal-spinner` }}>
<h3> {
viewLogin ? "Logging you in" : "Creating your account"
} </h3>
<Spinner />
</div>;
const Loader = ({ viewLogin }: { viewLogin: boolean }) => (
<div {...{ className: `fy-modal-page modal-spinner` }}>
<h3> {viewLogin ? "Logging you in" : "Creating your account"} </h3>
<Spinner />
</div>
);
export default function LoginModal({ handleClose, view, viewSwitch }: { handleClose: any, view: ModalView, viewSwitch: () => void }) {
const viewLogin = view === ModalView.Login;
const [status,statusSet] = useState(FetchStatus.paused);
export default function LoginModal({
handleClose,
view,
viewSwitch,
}: {
handleClose: any;
view: AccountModalView;
viewSwitch: () => void;
}) {
const viewLogin = view === AccountModalView.Login;
const [status, statusSet] = useState(FetchStatus.paused);
// const [viewLogin,viewLoginSet] = useState(false);
const [animating,animatingSet] = useState(false);
const { errorType, setProps: loginProps, login } = useLogin({
const [animating, animatingSet] = useState(false);
const {
errorType,
setProps: loginProps,
login,
} = useLogin({
onSuccess: () => {
Analytics.accountLoginSuccess();
handleClose();
handleClose();
},
status,
statusSet
statusSet,
});
const { setProps: signupProps, signup } = useSignup({
onSuccess: () => {
Analytics.accountSignupAttempt();
handleClose();
handleClose();
},
status,
statusSet
statusSet,
});
const index = status === FetchStatus.in_progress ? 2 : viewLogin ? 1: 0;
const index = status === FetchStatus.in_progress ? 2 : viewLogin ? 1 : 0;
const amt = 5;
const transitions = useTransition(index, {
config: { mass: 1, tension: 80, friction: 10 },
from: { opacity: 0, transform: `translateX(${ viewLogin ? amt : -amt }rem)` },
from: { opacity: 0, transform: `translateX(${viewLogin ? amt : -amt}rem)` },
enter: { opacity: 1, transform: `translateX(0)` },
leave: { opacity: 0, transform: `translateX(${ viewLogin ? -amt : amt }rem)` },
leave: {
opacity: 0,
transform: `translateX(${viewLogin ? -amt : amt}rem)`,
},
onRest: () => animatingSet(false),
onStart: () => animatingSet(true)
});
onStart: () => animatingSet(true),
});
return <div {...{ className: "fy-login-modal" }}>
{
transitions((style: any, i: number, state: any) => {
return (
<div {...{ className: "fy-login-modal" }}>
{transitions((style: any, i: number, state: any) => {
let isLeaving = state.phase === "leave";
let sharedProps = { animating, handleClose, isLeaving, style, viewLogin, viewSwitch };
let sharedProps = {
animating,
handleClose,
isLeaving,
style,
viewLogin,
viewSwitch,
};
switch(i) {
case 0: return <AniMod {...{ render: SignupView, signupProps, signup, ...sharedProps }}/>;
case 1: return <AniMod {...{ errorType, login, loginProps, render: LoginView, ...sharedProps }}/>;
case 2: return <AniMod {...{ render: Loader, ...sharedProps }}/>;
switch (i) {
case 0:
return (
<AniMod
{...{ render: SignupView, signupProps, signup, ...sharedProps }}
/>
);
case 1:
return (
<AniMod
{...{
errorType,
login,
loginProps,
render: LoginView,
...sharedProps,
}}
/>
);
case 2:
return <AniMod {...{ render: Loader, ...sharedProps }} />;
}
})
}
</div>;
};
})}
</div>
);
}
@@ -1,41 +0,0 @@
import React, { useState } from 'react';
import { AccountModalContext } from 'context';
import { useSession } from "hooks";
import { Modal } from "components/common";
import AccountModal from "components/layout/AccountModal";
import { ModalView } from "context/AccountModalContext";
interface Props {
children?: any;
}
export default function AccountModalProvider({ children }: Props) {
const { user } = useSession();
const [view,viewSet] = useState(ModalView.Closed);
const open = () => viewSet(ModalView.Signup);
const close = () => { viewSet(ModalView.Closed); console.log("🍏",);};
const viewSwitch = () => view === ModalView.Signup ? viewSet(ModalView.Login) : viewSet(ModalView.Signup);
const sessionCheck = () => {
if (user) {
return true;
} else {
open();
return false;
}
};
return <AccountModalContext.Provider {...{ value: { view, close, open, sessionCheck } }}>
{children}
{
<Modal {...{
content: AccountModal,
contentProps: { view, viewSwitch },
handleClose: close,
noHeader: true,
show: view > 0,
showButtons: false,
// title: "You need to login",
}}/>
}
</AccountModalContext.Provider>;
};
@@ -1 +0,0 @@
export { default } from "./AccountModalProvider";
@@ -19,6 +19,7 @@
.fy-modal-body {
width: 100%;
height: fit-content;
overflow: hidden;
background-color: $panel;
border-color: lighten($panel, 8%) !important;
border: 1px solid;
@@ -5,8 +5,9 @@ import "./ModalLayer.scss";
interface Props {
content?: React.ElementType | null;
contentProps?: any;
handleClose: () => void;
close: () => void;
killModal: boolean;
lockTint?: boolean;
modalOpen: boolean;
onModalCloseEnd: (x: any) => void;
}
@@ -14,10 +15,12 @@ interface Props {
export default function ModalLayer({
content: Content,
contentProps,
handleClose,
close,
lockTint,
modalOpen,
onModalCloseEnd,
}: Props) {
const mainClassName = "fy-modal-layer";
const tintTransition = useTransition(modalOpen, {
config: {
easing: modalOpen ? easings.easeOutQuad : easings.easeInQuad,
@@ -30,11 +33,27 @@ export default function ModalLayer({
});
return tintTransition(
(tinter, shade) =>
shade && (
<a.div {...{ className: "fy-modal-layer", style: { ...tinter } }}>
(tintStyle, modalIsOpen) =>
modalIsOpen && (
<a.div
{...{
className: mainClassName,
style: tintStyle,
onClick: ({ target }) => {
if (
!lockTint &&
target instanceof HTMLElement &&
target.className === mainClassName
) {
close();
}
},
}}
>
<div {...{ className: "fy-modal-body" }}>
{Content && <Content {...{ ...contentProps, handleClose }} />}
{Content && (
<Content {...{ ...contentProps, handleClose: close }} />
)}
</div>
</a.div>
)
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react";
import { ModalContext } from "context";
import React, { createContext, useEffect, useState } from "react";
import ModalLayer from "./ModalLayer";
import { isMobile } from "react-device-detect";
@@ -10,9 +9,24 @@ interface ModalProviderProps {
export interface ModalConfig {
component: React.ElementType;
lockTint?: boolean;
props?: any;
}
export interface ModalContextShared {
close: () => void;
modalOpen: boolean;
modalState: ModalConfig | null;
open: (cfg: ModalConfig) => void;
}
export const ModalContext = createContext<ModalContextShared>({
close: () => {},
open: () => {},
modalOpen: false,
modalState: null,
});
// how this works
//
// When modalState is set via open(), modalOpen is set to true to via useEffect
@@ -27,6 +41,7 @@ export default function ModalProvider({ children }: ModalProviderProps) {
const [modalState, modalStateSet] = useState<ModalConfig | null>(null);
const [modalOpen, modalOpenSet] = useState(false);
const [killModal, killModalSet] = useState(false);
const open = (cfg: ModalConfig) => modalStateSet(cfg);
const close = () => {
modalOpenSet(false);
@@ -40,19 +55,17 @@ export default function ModalProvider({ children }: ModalProviderProps) {
};
useEffect(() => {
if (!killModal && modalState && !modalOpen) {
modalOpenSet(true);
}
}, [killModal, modalOpen, modalState]);
// Prevent body scrolling when modal is open on mobile
useEffect(() => {
// Prevent body scrolling when modal is open on mobile
if (modalOpen && isMobile) {
document.body.classList.add("overflow-hidden");
} else {
document.body.classList.remove("overflow-hidden");
}
}, [modalOpen]);
if (!killModal && modalState && !modalOpen) {
modalOpenSet(true);
}
}, [killModal, modalOpen, modalState]);
return (
<ModalContext.Provider
@@ -63,10 +76,10 @@ export default function ModalProvider({ children }: ModalProviderProps) {
{...{
content: modalState?.component,
contentProps: modalState?.props,
handleClose: close,
close,
killModal,
lockTint: modalState?.lockTint,
modalOpen,
modalState,
onModalCloseEnd,
}}
/>
@@ -1 +1 @@
export { default } from "./ModalProvider";
export { default, ModalContext } from "./ModalProvider";
@@ -1,18 +1,17 @@
import AccountModalProvider from "./AccountModalProvider";
import CoreServicesProvider from "./CoreServicesProvider";
import InferenceJobsProvider, {
InferenceJobsContext,
} from "./InferenceJobsProvider";
import ModalProvider from "./ModalProvider/ModalProvider";
import ModalProvider, { ModalContext } from "./ModalProvider/ModalProvider";
import NotificationProvider from "./NotificationProvider";
import SessionProvider from "./SessionProvider";
export {
AccountModalProvider,
CoreServicesProvider,
InferenceJobsContext,
InferenceJobsProvider,
ModalProvider,
ModalContext,
NotificationProvider,
SessionProvider,
};
@@ -1,16 +0,0 @@
import { createContext } from 'react';
export enum ModalView {
Closed,
Signup,
Login
}
interface AccountModalContext { close: () => void, open: () => void, sessionCheck: () => boolean, view: ModalView, }
export default createContext<AccountModalContext>({
close: () => {},
open: () => {},
sessionCheck: () => false,
view: ModalView.Closed,
});
@@ -1,26 +0,0 @@
import { createContext } from "react";
export enum ModalView {
Closed,
Signup,
Login,
}
interface ModalConfig {
component: React.ElementType;
props?: any;
}
interface AccountModalContext {
close: () => void;
modalOpen: boolean;
modalState: ModalConfig | null;
open: (comp: any) => void;
}
export default createContext<AccountModalContext>({
close: () => {},
open: () => {},
modalOpen: false,
modalState: null,
});
@@ -1,13 +1,5 @@
import AccountModalContext from "./AccountModalContext";
import ModalContext from "./ModalContext";
import NotificationContext from "./NotificationContext";
import SessionContext from "./SessionContext";
import DomainConfigContext from "./DomainConfigContext";
export {
AccountModalContext,
ModalContext,
NotificationContext,
SessionContext,
DomainConfigContext,
};
export { NotificationContext, SessionContext, DomainConfigContext };
@@ -1,6 +1,6 @@
import { useContext } from 'react';
import { ModalContext } from 'context';
import { useContext } from "react";
import { ModalContext } from "components/providers";
export default function useInferenceJobs() {
return useContext(ModalContext);
};
}