From 6879a2d4523fbfc1ba5a4b81f9f28a20f7cd45e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20S=C3=A1nchez=20Yal=C3=AD?= Date: Fri, 25 Aug 2023 12:04:33 -0500 Subject: [PATCH] add Introductory Walkthrough App --- .../components/ArtWorkList/ArtWorkList.tsx | 7 +- .../ArtworkCard/ArtworkForm/ArtworkForm.tsx | 4 +- .../components/Auth/LoginForm/LoginForm.tsx | 4 +- .../Auth/RegisterForm/RegisterForm.tsx | 4 +- .../components/Auth/ResetForm/ResetForm.tsx | 4 +- .../Auth/SocialSignUp/SignUpWithGoogle.tsx | 5 +- .../CollectionForm/CollectionForm.tsx | 4 +- .../components/Collections/Collections.tsx | 5 +- .../EditProfileForm/EditProfileForm.tsx | 4 +- .../components/ImagineBase/ImagineBase.tsx | 4 + .../components/ImagineInput/ImagineInput.tsx | 4 +- .../components/OpenSource/OpenSource.tsx | 4 +- .../components/SearchForm/SearchForm.tsx | 4 +- .../WalkthroughApp/WalkthroughApp.module.scss | 118 +++++++++++++ .../WalkthroughApp/WalkthroughApp.tsx | 162 ++++++++++++++++++ .../Button.module.scss} | 37 +++- .../components/buttons/Button/Button.tsx | 78 +++++++++ .../buttons/ButtonPrimary/ButtonPrimary.tsx | 39 ----- .../ButtonSecondary.module.scss | 34 ---- .../ButtonSecondary/ButtonSecondary.tsx | 42 ----- morpheus-client/context/AuthContext.tsx | 11 +- .../SendToImagine/SendToImagine.tsx | 6 +- morpheus-client/models/models.ts | 1 + .../images/walkthroughApp/section-1.png | Bin 0 -> 91721 bytes .../images/walkthroughApp/section-2.png | Bin 0 -> 258201 bytes .../images/walkthroughApp/section-3.png | Bin 0 -> 38431 bytes .../images/walkthroughApp/section-4.png | Bin 0 -> 50144 bytes .../images/walkthroughApp/section-5.png | Bin 0 -> 136802 bytes .../images/walkthroughApp/section-6.png | Bin 0 -> 93329 bytes morpheus-client/services/auth.ts | 27 ++- morpheus-client/services/users.ts | 3 +- morpheus-client/styles/_colors.scss | 1 + morpheus-client/yarn.lock | 5 - .../7592af049bd2_add_is_new_user_parameter.py | 26 +++ morpheus-server/app/models/models.py | 1 + morpheus-server/app/models/schemas.py | 2 + .../app/repository/user_repository.py | 2 + 37 files changed, 485 insertions(+), 167 deletions(-) create mode 100644 morpheus-client/components/WalkthroughApp/WalkthroughApp.module.scss create mode 100644 morpheus-client/components/WalkthroughApp/WalkthroughApp.tsx rename morpheus-client/components/buttons/{ButtonPrimary/ButtonPrimary.module.scss => Button/Button.module.scss} (59%) create mode 100644 morpheus-client/components/buttons/Button/Button.tsx delete mode 100644 morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.tsx delete mode 100644 morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.module.scss delete mode 100644 morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.tsx create mode 100644 morpheus-client/public/images/walkthroughApp/section-1.png create mode 100644 morpheus-client/public/images/walkthroughApp/section-2.png create mode 100644 morpheus-client/public/images/walkthroughApp/section-3.png create mode 100644 morpheus-client/public/images/walkthroughApp/section-4.png create mode 100644 morpheus-client/public/images/walkthroughApp/section-5.png create mode 100644 morpheus-client/public/images/walkthroughApp/section-6.png create mode 100644 morpheus-server/app/migrations/versions/7592af049bd2_add_is_new_user_parameter.py diff --git a/morpheus-client/components/ArtWorkList/ArtWorkList.tsx b/morpheus-client/components/ArtWorkList/ArtWorkList.tsx index 17f6558e..95097e44 100644 --- a/morpheus-client/components/ArtWorkList/ArtWorkList.tsx +++ b/morpheus-client/components/ArtWorkList/ArtWorkList.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; -import ButtonSecondary from "../buttons/ButtonSecondary/ButtonSecondary"; +import Button from "../buttons/Button/Button"; import ArtworkCard from "../ArtworkCard/ArtworkCard"; import { ArtWork } from "@/models/models"; import styles from "./ArtWorkList.module.scss"; @@ -34,7 +34,7 @@ const ArtWorkList = (props: ArtWorkListProps) => { return (
-

Newest

+

Newest

@@ -52,11 +52,12 @@ const ArtWorkList = (props: ArtWorkListProps) => { )}
-
); diff --git a/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx b/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx index 499a30db..f51555ee 100644 --- a/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx +++ b/morpheus-client/components/ArtworkCard/ArtworkForm/ArtworkForm.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import ButtonPrimary from "../../buttons/ButtonPrimary/ButtonPrimary"; +import Button from "../../buttons/Button/Button"; import CollectionSelect from "../../CollectionSelect/CollectionSelect"; import { CloseIcon } from "../../icons/close"; import { saveArtWork, updateArtWork } from "@/services/artworks"; @@ -138,7 +138,7 @@ const ArtworkForm = (props: ArtworkFormProps) => { />
- { Forgot password? - { disabled={false} /> - {
- { @@ -19,12 +19,13 @@ export const SignUpWithGoogle = () => { }; return ( - } + variant="secondary" /> ); }; diff --git a/morpheus-client/components/CollectionForm/CollectionForm.tsx b/morpheus-client/components/CollectionForm/CollectionForm.tsx index 8f62e12c..a86e99a4 100644 --- a/morpheus-client/components/CollectionForm/CollectionForm.tsx +++ b/morpheus-client/components/CollectionForm/CollectionForm.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import InputTextArea from "../Inputs/InputTextArea/InputTextArea"; import InputFile from "../Inputs/InputFile/InputFile"; -import ButtonPrimary from "../buttons/ButtonPrimary/ButtonPrimary"; +import Button from "../buttons/Button/Button"; import { ImageIcon } from "@/components/icons/image"; import { useToastContext } from "@/context/ToastContext"; import { saveCollection, updateCollection } from "@/services/collection"; @@ -176,7 +176,7 @@ const CollectionForm = (props: CollectionFormProps) => {
- { )}
- diff --git a/morpheus-client/components/EditProfileForm/EditProfileForm.tsx b/morpheus-client/components/EditProfileForm/EditProfileForm.tsx index 5bc0e810..6a9130f5 100644 --- a/morpheus-client/components/EditProfileForm/EditProfileForm.tsx +++ b/morpheus-client/components/EditProfileForm/EditProfileForm.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import ButtonPrimary from "../buttons/ButtonPrimary/ButtonPrimary"; +import Button from "../buttons/Button/Button"; import InputTextArea from "../Inputs/InputTextArea/InputTextArea"; import InputFile from "../Inputs/InputFile/InputFile"; import { UserImage } from "../UserCard/UserCard"; @@ -110,7 +110,7 @@ const EditProfileForm = () => { styles={{ marginTop: "24px" }} /> - { const { img2imgFile, setImg2imgFile, maskFile, setMaskFile } = useImagine(); const { width } = useWindowDimensions(); + const { user } = useAuth(); const isMobile = width < MOBILE_SCREEN_WIDTH; const ImagineInputInstance = ( @@ -67,6 +70,7 @@ const ImagineBase = (props: MainContainerProps) => { {!isMobile && ImagineInputInstance} + {user?.is_new_user && } ); }; diff --git a/morpheus-client/components/ImagineInput/ImagineInput.tsx b/morpheus-client/components/ImagineInput/ImagineInput.tsx index f5e50968..1e92ea4d 100644 --- a/morpheus-client/components/ImagineInput/ImagineInput.tsx +++ b/morpheus-client/components/ImagineInput/ImagineInput.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import ButtonPrimary from "../buttons/ButtonPrimary/ButtonPrimary"; +import Button from "../buttons/Button/Button"; import InputTextArea from "../Inputs/InputTextArea/InputTextArea"; import { initialText } from "../Inputs/InputText/InputText"; import MagicPrompt from "../MagicPrompt/MagicPrompt"; @@ -54,7 +54,7 @@ const ImagineInput = (props: ImagineInputProps) => {
- { your own project needs.

- window.open("https://github.com/Monadical-SAS/Morpheus/fork") diff --git a/morpheus-client/components/SearchForm/SearchForm.tsx b/morpheus-client/components/SearchForm/SearchForm.tsx index 09534718..d18602f2 100644 --- a/morpheus-client/components/SearchForm/SearchForm.tsx +++ b/morpheus-client/components/SearchForm/SearchForm.tsx @@ -1,5 +1,5 @@ import InputSearch from "../Inputs/InputSearch/InputSearch"; -import ButtonPrimary from "../buttons/ButtonPrimary/ButtonPrimary"; +import Button from "../buttons/Button/Button"; import { useState } from "react"; import { searchArtWorks } from "@/services/artworks"; import { useToastContext } from "@/context/ToastContext"; @@ -43,7 +43,7 @@ const SearchForm = (props: SearchFormProps) => { showLabel={false} /> - + Welcome to Morpheus + Welcome to Morpheus +
+ ), + section2: ( +
+ Welcome to Morpheus +

Morpheus is an open source platform for exploring different visual AI models

+
+ ), + section3: ( +
+ Welcome to Morpheus +

You can use one of the many models provided, or add your own

+
+ ), + section4: ( +
+ Welcome to Morpheus +

+ Click the Magic Prompt button to augment your prompt with more descriptive, detailed, and stylized instructions, + resulting in more interesting images +

+
+ ), + section5: ( +
+ Welcome to Morpheus +

+ Use the settings to further modify your generated images, getting into the details of size, steps, and more +

+
+ ), + section6: ( +
+ Welcome to Morpheus +

+ Morpheus is also easily expanded for your own projects and needs. Just fork it on github! +

+
+ ), +}; + +const indicatorStyles = { + active: styles.indicatorActive, + inactive: styles.indicatorInactive, +}; + +type IndicatorStatus = keyof typeof indicatorStyles; + +const getIndicatorStyle = (status: IndicatorStatus) => { + return indicatorStyles[status]; +}; + +const sections = ["section1", "section2", "section3", "section4", "section5", "section6"]; + +const WalkthroughApp = () => { + const [sectionIndex, setSectionIndex] = useState(0); + const [showModal, setShowModal] = useState(false); + const isMobile = useWindowDimensions().width < MOBILE_SCREEN_WIDTH; + const { user } = useAuth(); + + useEffect(() => { + if (user) { + getUserInfo(user.email).then((response) => { + setShowModal(response.data.is_new_user); + }); + } + }, [user]); + + useEffect(() => { + if (showModal && sectionIndex === 0) { + updateUserInfo({ ...user, is_new_user: false }); + } + }, [user, sectionIndex, showModal]); + + const getPreviousSection = () => { + if (sectionIndex > 0) { + setSectionIndex(sectionIndex - 1); + } + }; + + const getNextSection = () => { + if (sectionIndex < sections.length - 1) { + setSectionIndex(sectionIndex + 1); + } + if (sectionIndex === sections.length - 1) { + setShowModal(false); + } + }; + + return ( + {}} + > +
+
+ {React.cloneElement(SlidesSections[sections[sectionIndex]], { key: sections[sectionIndex] })} +
+
0 ? styles.allButtons : styles.onlyRightButton}> + {sectionIndex > 0 && ( +
+
+
+ ); +}; + +export default WalkthroughApp; diff --git a/morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.module.scss b/morpheus-client/components/buttons/Button/Button.module.scss similarity index 59% rename from morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.module.scss rename to morpheus-client/components/buttons/Button/Button.module.scss index 3ef4c2b8..dfc4f4b7 100644 --- a/morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.module.scss +++ b/morpheus-client/components/buttons/Button/Button.module.scss @@ -1,21 +1,21 @@ @use "styles/colors"; @use "styles/media"; -.buttonPrimary { - width: 526px; - max-width: 100%; - height: 48px; +@mixin buttonBase { + cursor: pointer; box-sizing: border-box; display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 16px; - padding: 12px 57px; - cursor: pointer; - background: colors.$main-color; + width: 526px; + max-width: 100%; border: none; border-radius: 8px; + flex: none; + order: 0; + flex-grow: 0; @include media.mobile { width: 100%; @@ -29,9 +29,32 @@ align-items: center; gap: 16px; } +} + +.buttonPrimary { + @include buttonBase; + height: 48px; + padding: 12px 57px; + background: colors.$main-color; &.disabled { background: colors.$background-primary-4; cursor: not-allowed; } +} + +.buttonSecondary { + @include buttonBase; + height: 56px; + padding: 16px; + background: colors.$background-secondary; + border: 1px solid colors.$background-border; +} + +.buttonTertiary { + @include buttonBase; + height: 48px; + padding: 16px; + background: colors.$background-white; + border: 1px solid colors.$background-primary-5; } \ No newline at end of file diff --git a/morpheus-client/components/buttons/Button/Button.tsx b/morpheus-client/components/buttons/Button/Button.tsx new file mode 100644 index 00000000..a8a9a38d --- /dev/null +++ b/morpheus-client/components/buttons/Button/Button.tsx @@ -0,0 +1,78 @@ +import React, { CSSProperties } from "react"; +import Loader from "../../Loaders/LoaderCircle/Loader"; +import styles from "./Button.module.scss"; +import { cn } from "@/utils/styles"; + +const buttonVariants = { + primary: { + button: { + active: styles.buttonPrimary, + disabled: styles.disabled, + }, + text: { + active: "base-1 white", + }, + }, + secondary: { + button: { + active: styles.buttonSecondary, + disabled: styles.disabled, + }, + text: { + active: "base-1 white", + }, + }, + tertiary: { + button: { + active: styles.buttonTertiary, + disabled: styles.disabled, + }, + text: { + active: "base-1", + }, + }, +}; + +type buttonVariant = keyof typeof buttonVariants; + +const getVariantStyle = (variant?: buttonVariant) => { + return buttonVariants[variant ? variant : "primary"]; +}; + +interface ButtonProps { + loading: boolean; + disabled?: boolean; + text: string; + onClick: (event?: any) => any; + styles?: CSSProperties; + className?: any; + loaderColor?: string; + icon?: any; + variant?: buttonVariant; +} + +const Button = (props: ButtonProps) => { + return ( + + ); +}; + +export default Button; \ No newline at end of file diff --git a/morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.tsx b/morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.tsx deleted file mode 100644 index 23e8c264..00000000 --- a/morpheus-client/components/buttons/ButtonPrimary/ButtonPrimary.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { CSSProperties } from "react"; -import Loader from "../../Loaders/LoaderCircle/Loader"; -import styles from "./ButtonPrimary.module.scss"; - -interface ButtonPrimaryProps { - loading: boolean; - disabled?: boolean; - text: string; - onClick: (event?: any) => any; - styles?: CSSProperties; - className?: any; - loaderColor?: string; -} - -const ButtonPrimary = (props: ButtonPrimaryProps) => { - return ( - - ); -}; - -export default ButtonPrimary; diff --git a/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.module.scss b/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.module.scss deleted file mode 100644 index 9eca6785..00000000 --- a/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.module.scss +++ /dev/null @@ -1,34 +0,0 @@ -@use "styles/colors"; -@use "styles/media"; - -.buttonSecondary { - cursor: pointer; - box-sizing: border-box; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 16px; - gap: 16px; - width: 526px; - height: 56px; - background: colors.$background-secondary; - border: 1px solid colors.$background-border; - border-radius: 8px; - flex: none; - order: 0; - flex-grow: 0; - - @include media.mobile { - width: 100%; - padding: 16px 0; - } - - span { - width: 100%; - display: flex; - justify-content: center; - align-items: center; - gap: 16px; - } -} \ No newline at end of file diff --git a/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.tsx b/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.tsx deleted file mode 100644 index 9f2060c5..00000000 --- a/morpheus-client/components/buttons/ButtonSecondary/ButtonSecondary.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React, { CSSProperties } from "react"; -import Loader from "../../Loaders/LoaderCircle/Loader"; -import styles from "./ButtonSecondary.module.scss"; - -interface ButtonSecondaryProps { - loading: boolean; - disabled?: boolean; - text: string; - onClick: (event?: any) => any; - styles?: CSSProperties; - className?: any; - icon?: any; -} - -const ButtonSecondary = (props: ButtonSecondaryProps) => { - return ( - - ); -}; - -export default ButtonSecondary; diff --git a/morpheus-client/context/AuthContext.tsx b/morpheus-client/context/AuthContext.tsx index c89ba882..87f42089 100644 --- a/morpheus-client/context/AuthContext.tsx +++ b/morpheus-client/context/AuthContext.tsx @@ -51,7 +51,7 @@ const AuthContext = createContext(defaultState); const AuthProvider = (props: { children: ReactNode }) => { const router = useRouter(); - const { showErrorAlert } = useToastContext(); + const { showErrorAlert, showInfoAlert } = useToastContext(); const [authLoading, setAuthLoading] = useState(true); const [authOption, setAuthOption] = useState(AuthOption.Login); @@ -83,7 +83,7 @@ const AuthProvider = (props: { children: ReactNode }) => { const registerWithEmailAndPassword = (user: UserRegistration): Promise => { return signUpWithEmailAndPasswordFirebase(user) .then((response) => { - loadOrCreateMorpheusUser({ ...response, displayName: user.name }); + loadOrCreateMorpheusUser({ ...response.user, displayName: user.name }); }) .catch((error) => { showErrorAlert(error.message); @@ -94,7 +94,7 @@ const AuthProvider = (props: { children: ReactNode }) => { return new Promise((resolve, reject) => { loginWithEmailAndPasswordFirebase(user) .then((response: any) => { - loadOrCreateMorpheusUser(response); + loadOrCreateMorpheusUser(response.user); }) .catch((error) => { showErrorAlert(error.message); @@ -122,6 +122,7 @@ const AuthProvider = (props: { children: ReactNode }) => { name: firebaseUser.displayName, email: firebaseUser.email, phone: firebaseUser.phoneNumber, + is_new_user: firebaseUser.isNewUser, }; if (!user.email) { showErrorAlert("Email is required"); @@ -136,7 +137,7 @@ const AuthProvider = (props: { children: ReactNode }) => { if (response.success) { setUser(response.data); } else { - showErrorAlert(response.error || "An error occurred while loading the user data"); + showInfoAlert("Failed to load user data. Please try again later"); } }) .catch(() => { @@ -151,7 +152,7 @@ const AuthProvider = (props: { children: ReactNode }) => { setUser(response.data); setLocalUser(response.data); } else { - showErrorAlert("An error occurred while loading the user data"); + showInfoAlert("Failed to load user data. Please try again later"); } }) .catch(() => { diff --git a/morpheus-client/excalidraw/components/SendToImagine/SendToImagine.tsx b/morpheus-client/excalidraw/components/SendToImagine/SendToImagine.tsx index 0253dad4..a94cb84f 100644 --- a/morpheus-client/excalidraw/components/SendToImagine/SendToImagine.tsx +++ b/morpheus-client/excalidraw/components/SendToImagine/SendToImagine.tsx @@ -4,7 +4,7 @@ import { exportToBlob } from "../../packages/utils"; import { useImagine } from "@/context/ImagineContext"; import { getFileFromBlob } from "@/utils/images"; import { useApp, useExcalidrawAppState, useExcalidrawElements } from "../App"; -import ButtonPrimary from "@/components/buttons/ButtonPrimary/ButtonPrimary"; +import Button from "@/components/buttons/Button/Button"; import styles from "./SendToImagine.module.scss"; export const SendImageToImagine = () => { @@ -35,8 +35,8 @@ export const SendImageToImagine = () => { return (
- - +