diff --git a/frontend/lib/components/ui/Modal/Modal.module.scss b/frontend/lib/components/ui/Modal/Modal.module.scss
index 800aaba4b..15a1c09f3 100644
--- a/frontend/lib/components/ui/Modal/Modal.module.scss
+++ b/frontend/lib/components/ui/Modal/Modal.module.scss
@@ -24,6 +24,8 @@
box-shadow: BoxShadow.$medium;
max-width: 90vw;
overflow: scroll;
+ width: 35vw;
+ height: 80vh;
&.big_modal {
width: 40vw;
@@ -36,9 +38,7 @@
}
@media (max-width: ScreenSizes.$small) {
- &.big_modal {
- width: 90vw;
- }
+ width: 90vw;
}
.close_button_wrapper {
diff --git a/frontend/lib/components/ui/Modal/Modal.tsx b/frontend/lib/components/ui/Modal/Modal.tsx
index ef21ff794..a2b59beaa 100644
--- a/frontend/lib/components/ui/Modal/Modal.tsx
+++ b/frontend/lib/components/ui/Modal/Modal.tsx
@@ -20,6 +20,7 @@ type CommonModalProps = {
isOpen?: undefined;
setOpen?: undefined;
bigModal?: boolean;
+ unclosable?: boolean;
unforceWhite?: boolean;
};
@@ -30,6 +31,31 @@ type ModalProps =
setOpen: (isOpen: boolean) => void;
});
+const handleInteractOutside = (unclosable: boolean, event: Event) => {
+ if (unclosable) {
+ event.preventDefault();
+ }
+};
+
+const handleModalContentAnimation = (
+ isOpen: boolean,
+ bigModal: boolean,
+ unforceWhite: boolean
+) => {
+ const initialAnimation = { opacity: 0, y: "-40%" };
+ const animateAnimation = { opacity: 1, y: "0%" };
+ const exitAnimation = { opacity: 0, y: "40%" };
+
+ return {
+ initial: initialAnimation,
+ animate: animateAnimation,
+ exit: exitAnimation,
+ className: `${styles.modal_content_wrapper} ${
+ bigModal ? styles.big_modal : ""
+ } ${unforceWhite ? styles.white : ""}`,
+ };
+};
+
export const Modal = ({
title,
desc,
@@ -39,6 +65,7 @@ export const Modal = ({
isOpen: customIsOpen,
setOpen: customSetOpen,
bigModal,
+ unclosable,
unforceWhite,
}: ModalProps): JSX.Element => {
const [isOpen, setOpen] = useState(false);
@@ -62,14 +89,19 @@ export const Modal = ({
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
-
+
+ handleInteractOutside(!!unclosable, event)
+ }
+ >
)}
-
-
-
+ {!unclosable && (
+
+
+
+ )}
diff --git a/frontend/lib/context/OnboardingProvider/Onboarding-provider.tsx b/frontend/lib/context/OnboardingProvider/Onboarding-provider.tsx
new file mode 100644
index 000000000..a0e93ca6e
--- /dev/null
+++ b/frontend/lib/context/OnboardingProvider/Onboarding-provider.tsx
@@ -0,0 +1,36 @@
+import { createContext, useEffect, useState } from "react";
+
+import { useUserData } from "@/lib/hooks/useUserData";
+
+export type OnboardingContextType = {
+ isOnboardingModalOpened: boolean;
+ setIsOnboardingModalOpened: React.Dispatch>;
+};
+
+export const OnboardingContext = createContext<
+ OnboardingContextType | undefined
+>(undefined);
+
+export const OnboardingProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+}): JSX.Element => {
+ const [isOnboardingModalOpened, setIsOnboardingModalOpened] = useState(false);
+ const { userIdentityData } = useUserData();
+
+ useEffect(() => {
+ setIsOnboardingModalOpened(!!userIdentityData?.onboarded);
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/frontend/lib/context/OnboardingProvider/hooks/useOnboardingContext.tsx b/frontend/lib/context/OnboardingProvider/hooks/useOnboardingContext.tsx
new file mode 100644
index 000000000..b4adeb811
--- /dev/null
+++ b/frontend/lib/context/OnboardingProvider/hooks/useOnboardingContext.tsx
@@ -0,0 +1,17 @@
+import { useContext } from "react";
+
+import {
+ OnboardingContext,
+ OnboardingContextType,
+} from "../Onboarding-provider";
+
+export const useOnboardingContext = (): OnboardingContextType => {
+ const context = useContext(OnboardingContext);
+ if (context === undefined) {
+ throw new Error(
+ "useOnboardingContext must be used within a OnboardingProvider"
+ );
+ }
+
+ return context;
+};
diff --git a/frontend/lib/helpers/iconList.ts b/frontend/lib/helpers/iconList.ts
index 6644f1283..c39af2aae 100644
--- a/frontend/lib/helpers/iconList.ts
+++ b/frontend/lib/helpers/iconList.ts
@@ -27,9 +27,11 @@ import {
} from "react-icons/fa";
import { FaInfo } from "react-icons/fa6";
import { FiUpload } from "react-icons/fi";
+import { HiBuildingOffice } from "react-icons/hi2";
import {
IoIosAdd,
IoIosHelpCircleOutline,
+ IoIosRadio,
IoMdClose,
IoMdLogOut,
} from "react-icons/io";
@@ -50,6 +52,7 @@ import {
LuChevronLeft,
LuChevronRight,
LuCopy,
+ LuGoal,
LuPlusCircle,
LuSearch,
} from "react-icons/lu";
@@ -63,6 +66,7 @@ import {
MdOutlineModeEditOutline,
MdUploadFile,
} from "react-icons/md";
+import { PiOfficeChairFill } from "react-icons/pi";
import { RiHashtag } from "react-icons/ri";
import { SlOptions } from "react-icons/sl";
import { TbNetwork } from "react-icons/tb";
@@ -73,6 +77,7 @@ export const iconList: { [name: string]: IconType } = {
addWithoutCircle: IoIosAdd,
brain: LuBrain,
brainCircuit: LuBrainCircuit,
+ chair: PiOfficeChairFill,
chat: BsChatLeftText,
check: FaCheck,
checkCircle: FaCheckCircle,
@@ -93,6 +98,7 @@ export const iconList: { [name: string]: IconType } = {
flag: CiFlag1,
followUp: IoArrowUpCircleOutline,
github: FaGithub,
+ goal: LuGoal,
graph: VscGraph,
hashtag: RiHashtag,
help: IoIosHelpCircleOutline,
@@ -105,10 +111,12 @@ export const iconList: { [name: string]: IconType } = {
loader: AiOutlineLoading3Quarters,
logout: IoMdLogOut,
moon: FaMoon,
+ office: HiBuildingOffice,
options: SlOptions,
paragraph: BsTextParagraph,
prompt: FaRegKeyboard,
redirection: BsArrowRightShort,
+ radio: IoIosRadio,
robot: LiaRobotSolid,
search: LuSearch,
settings: IoSettingsSharp,
diff --git a/frontend/lib/hooks/useUserData.ts b/frontend/lib/hooks/useUserData.ts
index 0be4324dd..4c204b4de 100644
--- a/frontend/lib/hooks/useUserData.ts
+++ b/frontend/lib/hooks/useUserData.ts
@@ -1,18 +1,25 @@
import { useQuery } from "@tanstack/react-query";
-import { USER_DATA_KEY } from "../api/user/config";
+import { USER_DATA_KEY, USER_IDENTITY_DATA_KEY } from "../api/user/config";
import { useUserApi } from "../api/user/useUserApi";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useUserData = () => {
const { getUser } = useUserApi();
+ const { getUserIdentity } = useUserApi();
const { data: userData } = useQuery({
queryKey: [USER_DATA_KEY],
queryFn: getUser,
});
+ const { data: userIdentityData } = useQuery({
+ queryKey: [USER_IDENTITY_DATA_KEY],
+ queryFn: getUserIdentity,
+ });
+
return {
userData,
+ userIdentityData,
};
};
diff --git a/supabase/migrations/20240314005817_user_identity_company_info.sql b/supabase/migrations/20240314005817_user_identity_company_info.sql
new file mode 100644
index 000000000..93323709b
--- /dev/null
+++ b/supabase/migrations/20240314005817_user_identity_company_info.sql
@@ -0,0 +1,7 @@
+create type "public"."user_identity_company_size" as enum ('1-10', '10-25', '25-50', '50-100', '100-250', '250-500', '500-1000', '1000-5000', '+5000');
+
+alter table "public"."user_identity" add column "company_size" user_identity_company_size;
+
+alter table "public"."user_identity" add column "role_in_company" text;
+
+
diff --git a/supabase/migrations/20240316195514_usage_purpose.sql b/supabase/migrations/20240316195514_usage_purpose.sql
new file mode 100644
index 000000000..657e89e43
--- /dev/null
+++ b/supabase/migrations/20240316195514_usage_purpose.sql
@@ -0,0 +1,5 @@
+alter table "public"."user_identity" drop column "role_in_company";
+
+alter table "public"."user_identity" add column "usage_purpose" text;
+
+