diff --git a/frontend/src/assets/theme.js b/frontend/src/assets/theme.js index 84f7c35e..9dbb0d14 100644 --- a/frontend/src/assets/theme.js +++ b/frontend/src/assets/theme.js @@ -1,6 +1,14 @@ import { createTheme } from "@mui/material"; const theme = createTheme({ + palette: { + primary: { + main: "#7f56d9", + }, + background: { + default: "#FFFFFF", + }, + }, components: { MuiAppBar: { styleOverrides: { diff --git a/frontend/src/components/List/List.jsx b/frontend/src/components/List/List.jsx new file mode 100644 index 00000000..b6aa5797 --- /dev/null +++ b/frontend/src/components/List/List.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ListItem from './ListItem/ListItem'; + +const List = ({ items, onSelectItem }) => { + return ( +
+ {items.map(item => ( + onSelectItem(item.idItem)} + onDelete={item.onDelete} + onEdit={item.onEdit} + /> + ))} +
+ ); +}; + +List.propTypes = { + items: PropTypes.arrayOf(PropTypes.object), + onSelectItem: PropTypes.func, +}; + +export default List; diff --git a/frontend/src/components/List/ListItem/ListItem.css b/frontend/src/components/List/ListItem/ListItem.css new file mode 100644 index 00000000..2cda96e7 --- /dev/null +++ b/frontend/src/components/List/ListItem/ListItem.css @@ -0,0 +1,81 @@ +.list-item { + display: flex; + justify-content: space-between; + align-items: center; + width: 758px; + height: 78px; + padding: 10px; + border: 1px solid var(--grey-border); + border-radius: 10px; + cursor: pointer; + margin-bottom: 30px; +} + +.list-item:hover, +.list-item:focus { + border: 1px solid var(--main-purple); +} + +.list-item-info { + display: flex; + flex-direction: column; + margin-left: 10px; +} + +.list-item-header { + display: flex; + align-items: center; +} + +.list-item-icon-container { + display: flex; + align-items: center; + position: relative; + width: 24px; + height: 24px; + margin-right: 10px; +} + +.list-item-icon { + width: 12px; + height: 12px; + color: #7F56D9; +} + +.list-item-dot { + position: absolute; + top: 50%; + left: 50%; + width: 10px; + height: 10px; + background-color: #FFFFFF; + border-radius: 50%; + transform: translate(-50%, -50%); +} + +.list-item-info h4 { + margin: 0; + font-size: 16px; + color: #344054; +} + +.list-item-info p { + margin: 2px 0 0 33px; + font-size: 14px; + color: #667085; +} + +.item-id { + margin: 2px 0 0 0; + font-size: 12px; + color: #667085; +} + +.list-item-actions { + display: flex; + align-items: center; +} + +.list-item-actions .MuiIconButton-root { + color: #344054; +} diff --git a/frontend/src/components/List/ListItem/ListItem.jsx b/frontend/src/components/List/ListItem/ListItem.jsx new file mode 100644 index 00000000..007eadde --- /dev/null +++ b/frontend/src/components/List/ListItem/ListItem.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { IconButton, useTheme } from '@mui/material'; +import DeleteIcon from '@mui/icons-material/Delete'; +import SettingsIcon from '@mui/icons-material/Settings'; +import CircleIcon from '@mui/icons-material/Circle'; +import './ListItem.css'; + +const ListItem = ({ title, text, id, onClick, onDelete, onEdit }) => { + const theme = useTheme(); + + return ( +
+
+
+
+ +
+
+

{title}

+
+ {text &&

{text}

} + {id &&

ID: {id}

} +
+
+ + + + + + +
+
+ ); +}; + +ListItem.propTypes = { + title: PropTypes.string, + text: PropTypes.string, + id: PropTypes.string, + onClick: PropTypes.func, + onDelete: PropTypes.func, + onEdit: PropTypes.func, +}; + +export default ListItem; diff --git a/frontend/src/components/TourComponents/ConfirmationPopup/ConfirmationPopup.jsx b/frontend/src/components/TourComponents/ConfirmationPopup/ConfirmationPopup.jsx new file mode 100644 index 00000000..b02a919d --- /dev/null +++ b/frontend/src/components/TourComponents/ConfirmationPopup/ConfirmationPopup.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button } from '@mui/material'; + +const ConfirmationPopup = ({ open, onConfirm, onCancel }) => { + return ( + + Confirm Action + + Are you sure you want to perform this action? + + + + + + + ); +}; + +ConfirmationPopup.propTypes = { + open: PropTypes.bool.isRequired, + onConfirm: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, +}; + +export default ConfirmationPopup; diff --git a/frontend/src/components/TourComponents/ContentArea/ContentArea.jsx b/frontend/src/components/TourComponents/ContentArea/ContentArea.jsx new file mode 100644 index 00000000..f2e4d5cc --- /dev/null +++ b/frontend/src/components/TourComponents/ContentArea/ContentArea.jsx @@ -0,0 +1,13 @@ + +import React from 'react'; +import PropTypes from 'prop-types'; + +const ContentArea = ({ children }) => { + return
{children}
; +}; + +ContentArea.propTypes = { + children: PropTypes.node, +}; + +export default ContentArea; diff --git a/frontend/src/components/TourComponents/ContentHeader/ContentHeader.jsx b/frontend/src/components/TourComponents/ContentHeader/ContentHeader.jsx new file mode 100644 index 00000000..424a0733 --- /dev/null +++ b/frontend/src/components/TourComponents/ContentHeader/ContentHeader.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const ContentHeader = ({ title }) => { + return

{title}

; +}; + +ContentHeader.propTypes = { + title: PropTypes.string, +}; + +export default ContentHeader; diff --git a/frontend/src/components/TourComponents/InfoTooltip/InfoTooltip.jsx b/frontend/src/components/TourComponents/InfoTooltip/InfoTooltip.jsx new file mode 100644 index 00000000..d291b127 --- /dev/null +++ b/frontend/src/components/TourComponents/InfoTooltip/InfoTooltip.jsx @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Tooltip, IconButton } from '@mui/material'; +import InfoIcon from '@mui/icons-material/Info'; + +const InfoTooltip = ({ text, title }) => { + return ( + + + + + + ); +}; + +InfoTooltip.propTypes = { + text: PropTypes.string, + title: PropTypes.string, +}; + +export default InfoTooltip; diff --git a/frontend/src/components/TourComponents/TourDescriptionText/TourDescriptionText.jsx b/frontend/src/components/TourComponents/TourDescriptionText/TourDescriptionText.jsx new file mode 100644 index 00000000..ce8a5a84 --- /dev/null +++ b/frontend/src/components/TourComponents/TourDescriptionText/TourDescriptionText.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const TourDescriptionText = ({ description }) => { + return

{description}

; +}; + +TourDescriptionText.propTypes = { + description: PropTypes.string, +}; + +export default TourDescriptionText; diff --git a/frontend/src/scenes/home/Home.jsx b/frontend/src/scenes/home/Home.jsx index 654d9d8d..aa066bc2 100644 --- a/frontend/src/scenes/home/Home.jsx +++ b/frontend/src/scenes/home/Home.jsx @@ -27,4 +27,4 @@ const Home = () => { ); }; -export default Home; +export default Home; \ No newline at end of file diff --git a/frontend/src/scenes/tours/ProductTour.jsx b/frontend/src/scenes/tours/ProductTour.jsx new file mode 100644 index 00000000..f5fe9820 --- /dev/null +++ b/frontend/src/scenes/tours/ProductTour.jsx @@ -0,0 +1,81 @@ +import React, { useState, useEffect } from 'react'; +import List from '../../components/List/List'; +import ContentArea from '../../components/TourComponents/ContentArea/ContentArea'; +import ContentHeader from '../../components/TourComponents/ContentHeader/ContentHeader'; +import ConfirmationPopup from '../../components/TourComponents/ConfirmationPopup/ConfirmationPopup'; +import Button from '../../components/Button/Button'; +import './ProductTourStyles.css'; +import TourDescriptionText from '../../components/TourComponents/TourDescriptionText/TourDescriptionText'; +import InfoTooltip from '../../components/TourComponents/InfoTooltip/InfoTooltip'; + +const TourPage = ({ items }) => { + const [selectedItem, setSelectedItem] = useState(null); + const [isPopupOpen, setPopupOpen] = useState(false); + const [showDemoItems, setShowDemoItems] = useState(false); + + useEffect(() => { + setShowDemoItems(items.length === 0); + }, [items]); + + const handleSelect = (idItem) => { + setSelectedItem(idItem); + }; + + const handleDelete = () => { + setPopupOpen(false); + }; + + const handleOpenPopup = () => { + setPopupOpen(true); + }; + + const handleClosePopup = () => { + setPopupOpen(false); + }; + + const handleCreateItem = () => { + }; + + const demoItems = [ + { + title: 'Main dashboard - first login tour', + timestamp: '10:00 AM', + idItem: '12548', + text: 'This pops up the first time the user logins to the dashboard.', + onDelete: () => { }, + onEdit: () => { } + }, + ]; + + return ( +
+
+ +
+
+ + + + + +
+
+

What is a product tour?

+

+ A product onboarding tour is a guided walkthrough or tutorial that introduces users to a new product or service. + It typically occurs when a user first signs up or logs into the product. + The purpose of the onboarding tour is to familiarize users with the key features, functionalities, and benefits of the product in order to enhance their understanding. + During the onboarding tour, users are typically shown around the interface, given demonstrations of how to perform key tasks, and provided with explanations of important features. +

+
+
+
+ {/* + */} + +
+ ); +}; + +export default TourPage; diff --git a/frontend/src/scenes/tours/ProductTourStyles.css b/frontend/src/scenes/tours/ProductTourStyles.css new file mode 100644 index 00000000..89a8d827 --- /dev/null +++ b/frontend/src/scenes/tours/ProductTourStyles.css @@ -0,0 +1,45 @@ +.product-page-container { + padding: 2% 3%; +} + +.product-page-header { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + margin-bottom: 20px; +} + +.product-page { + display: flex; + align-items: flex-start; +} + +.content-area { + flex: 2; + margin-right: 20px; +} + +.tour-info-container { + flex: 1; +} + +.tour-info-box { + padding: 16px; + border-radius: 8px; + border: 1px solid var(--grey-border); +} + +.tour-info-box h4 { + margin-top: 0; + color: var(--main-purple); +} + +.tour-info-box p { + margin-bottom: 0; + color: #6b7280; +} + +.create-tour-button { + padding: 8px 16px; +} diff --git a/frontend/src/scenes/tours/ToursDefaultPage.jsx b/frontend/src/scenes/tours/ToursDefaultPage.jsx index e8e5013c..a54a0318 100644 --- a/frontend/src/scenes/tours/ToursDefaultPage.jsx +++ b/frontend/src/scenes/tours/ToursDefaultPage.jsx @@ -1,26 +1,37 @@ -import CreateActivityButton from "../../components/CreateActivityButton/CreateActivityButton" -import HomePageTemplate from "../../components/templates/HomePageTemplate" +import React, { useState } from 'react'; +import CreateActivityButton from "../../components/CreateActivityButton/CreateActivityButton"; +import HomePageTemplate from "../../components/templates/HomePageTemplate"; import { ACTIVITY_TYPES } from "../../data/CreateActivityButtonData"; import ParagraphCSS from "../../components/ParagraphCSS/ParagraphCSS"; +import TourPage from './ProductTour'; const ToursDefaultPage = () => { + const [showTourPage, setShowTourPage] = useState(false); + + const handleButtonClick = () => { + setShowTourPage(true); + }; + const style = { "display": "flex", "flex-direction": "column", "width": "100%", "justify-content": "center", "align-items": "center", - } + }; + return ( -
- - -
- + {showTourPage ? ( + + ) : ( +
+ + +
+ )}
- ) -} - -export default ToursDefaultPage + ); +}; +export default ToursDefaultPage;