Skip to content

Commit cc17d26

Browse files
Merge pull request #108 from bluewave-labs/feature/Issue-75-Develop-a-page-for-creating-new-product-tour-items
Feature/issue 75 develop a page for creating new product tour items
2 parents 9edc0a5 + 163fdd1 commit cc17d26

File tree

13 files changed

+397
-13
lines changed

13 files changed

+397
-13
lines changed

frontend/src/assets/theme.js

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import { createTheme } from "@mui/material";
22

33
const theme = createTheme({
4+
palette: {
5+
primary: {
6+
main: "#7f56d9",
7+
},
8+
background: {
9+
default: "#FFFFFF",
10+
},
11+
},
412
components: {
513
MuiAppBar: {
614
styleOverrides: {

frontend/src/components/List/List.jsx

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import ListItem from './ListItem/ListItem';
4+
5+
const List = ({ items, onSelectItem }) => {
6+
return (
7+
<div>
8+
{items.map(item => (
9+
<ListItem
10+
key={item.idItem}
11+
title={item.title}
12+
text={item.text}
13+
id={item.idItem}
14+
onClick={() => onSelectItem(item.idItem)}
15+
onDelete={item.onDelete}
16+
onEdit={item.onEdit}
17+
/>
18+
))}
19+
</div>
20+
);
21+
};
22+
23+
List.propTypes = {
24+
items: PropTypes.arrayOf(PropTypes.object),
25+
onSelectItem: PropTypes.func,
26+
};
27+
28+
export default List;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
.list-item {
2+
display: flex;
3+
justify-content: space-between;
4+
align-items: center;
5+
width: 758px;
6+
height: 78px;
7+
padding: 10px;
8+
border: 1px solid var(--grey-border);
9+
border-radius: 10px;
10+
cursor: pointer;
11+
margin-bottom: 30px;
12+
}
13+
14+
.list-item:hover,
15+
.list-item:focus {
16+
border: 1px solid var(--main-purple);
17+
}
18+
19+
.list-item-info {
20+
display: flex;
21+
flex-direction: column;
22+
margin-left: 10px;
23+
}
24+
25+
.list-item-header {
26+
display: flex;
27+
align-items: center;
28+
}
29+
30+
.list-item-icon-container {
31+
display: flex;
32+
align-items: center;
33+
position: relative;
34+
width: 24px;
35+
height: 24px;
36+
margin-right: 10px;
37+
}
38+
39+
.list-item-icon {
40+
width: 12px;
41+
height: 12px;
42+
color: #7F56D9;
43+
}
44+
45+
.list-item-dot {
46+
position: absolute;
47+
top: 50%;
48+
left: 50%;
49+
width: 10px;
50+
height: 10px;
51+
background-color: #FFFFFF;
52+
border-radius: 50%;
53+
transform: translate(-50%, -50%);
54+
}
55+
56+
.list-item-info h4 {
57+
margin: 0;
58+
font-size: 16px;
59+
color: #344054;
60+
}
61+
62+
.list-item-info p {
63+
margin: 2px 0 0 33px;
64+
font-size: 14px;
65+
color: #667085;
66+
}
67+
68+
.item-id {
69+
margin: 2px 0 0 0;
70+
font-size: 12px;
71+
color: #667085;
72+
}
73+
74+
.list-item-actions {
75+
display: flex;
76+
align-items: center;
77+
}
78+
79+
.list-item-actions .MuiIconButton-root {
80+
color: #344054;
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { IconButton, useTheme } from '@mui/material';
4+
import DeleteIcon from '@mui/icons-material/Delete';
5+
import SettingsIcon from '@mui/icons-material/Settings';
6+
import CircleIcon from '@mui/icons-material/Circle';
7+
import './ListItem.css';
8+
9+
const ListItem = ({ title, text, id, onClick, onDelete, onEdit }) => {
10+
const theme = useTheme();
11+
12+
return (
13+
<div className="list-item" onClick={onClick}>
14+
<div className="list-item-info">
15+
<div className="list-item-header">
16+
<div className="list-item-icon-container">
17+
<CircleIcon className="list-item-icon" style={{ fill: theme.palette.primary.main }} />
18+
<div className="list-item-dot" style={{ backgroundColor: theme.palette.background.default }}></div>
19+
</div>
20+
<h4>{title}</h4>
21+
</div>
22+
{text && <p>{text}</p>}
23+
{id && <p className="item-id">ID: {id}</p>}
24+
</div>
25+
<div className="list-item-actions">
26+
<IconButton onClick={onEdit}>
27+
<SettingsIcon />
28+
</IconButton>
29+
<IconButton onClick={onDelete}>
30+
<DeleteIcon />
31+
</IconButton>
32+
</div>
33+
</div>
34+
);
35+
};
36+
37+
ListItem.propTypes = {
38+
title: PropTypes.string,
39+
text: PropTypes.string,
40+
id: PropTypes.string,
41+
onClick: PropTypes.func,
42+
onDelete: PropTypes.func,
43+
onEdit: PropTypes.func,
44+
};
45+
46+
export default ListItem;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button } from '@mui/material';
4+
5+
const ConfirmationPopup = ({ open, onConfirm, onCancel }) => {
6+
return (
7+
<Dialog open={open} onClose={onCancel}>
8+
<DialogTitle>Confirm Action</DialogTitle>
9+
<DialogContent>
10+
<DialogContentText>Are you sure you want to perform this action?</DialogContentText>
11+
</DialogContent>
12+
<DialogActions>
13+
<Button onClick={onCancel}>Cancel</Button>
14+
<Button onClick={onConfirm} color="primary">Confirm</Button>
15+
</DialogActions>
16+
</Dialog>
17+
);
18+
};
19+
20+
ConfirmationPopup.propTypes = {
21+
open: PropTypes.bool.isRequired,
22+
onConfirm: PropTypes.func.isRequired,
23+
onCancel: PropTypes.func.isRequired,
24+
};
25+
26+
export default ConfirmationPopup;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
5+
const ContentArea = ({ children }) => {
6+
return <div className="content-area">{children}</div>;
7+
};
8+
9+
ContentArea.propTypes = {
10+
children: PropTypes.node,
11+
};
12+
13+
export default ContentArea;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
const ContentHeader = ({ title }) => {
5+
return <h2 className="content-header">{title}</h2>;
6+
};
7+
8+
ContentHeader.propTypes = {
9+
title: PropTypes.string,
10+
};
11+
12+
export default ContentHeader;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Tooltip, IconButton } from '@mui/material';
4+
import InfoIcon from '@mui/icons-material/Info';
5+
6+
const InfoTooltip = ({ text, title }) => {
7+
return (
8+
<Tooltip title={text}>
9+
<IconButton>
10+
<InfoIcon />
11+
</IconButton>
12+
</Tooltip>
13+
);
14+
};
15+
16+
InfoTooltip.propTypes = {
17+
text: PropTypes.string,
18+
title: PropTypes.string,
19+
};
20+
21+
export default InfoTooltip;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
const TourDescriptionText = ({ description }) => {
5+
return <p className="tour-description-text">{description}</p>;
6+
};
7+
8+
TourDescriptionText.propTypes = {
9+
description: PropTypes.string,
10+
};
11+
12+
export default TourDescriptionText;

frontend/src/scenes/home/Home.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ const Home = () => {
2727
);
2828
};
2929

30-
export default Home;
30+
export default Home;
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import React, { useState, useEffect } from 'react';
2+
import List from '../../components/List/List';
3+
import ContentArea from '../../components/TourComponents/ContentArea/ContentArea';
4+
import ContentHeader from '../../components/TourComponents/ContentHeader/ContentHeader';
5+
import ConfirmationPopup from '../../components/TourComponents/ConfirmationPopup/ConfirmationPopup';
6+
import Button from '../../components/Button/Button';
7+
import './ProductTourStyles.css';
8+
import TourDescriptionText from '../../components/TourComponents/TourDescriptionText/TourDescriptionText';
9+
import InfoTooltip from '../../components/TourComponents/InfoTooltip/InfoTooltip';
10+
11+
const TourPage = ({ items }) => {
12+
const [selectedItem, setSelectedItem] = useState(null);
13+
const [isPopupOpen, setPopupOpen] = useState(false);
14+
const [showDemoItems, setShowDemoItems] = useState(false);
15+
16+
useEffect(() => {
17+
setShowDemoItems(items.length === 0);
18+
}, [items]);
19+
20+
const handleSelect = (idItem) => {
21+
setSelectedItem(idItem);
22+
};
23+
24+
const handleDelete = () => {
25+
setPopupOpen(false);
26+
};
27+
28+
const handleOpenPopup = () => {
29+
setPopupOpen(true);
30+
};
31+
32+
const handleClosePopup = () => {
33+
setPopupOpen(false);
34+
};
35+
36+
const handleCreateItem = () => {
37+
};
38+
39+
const demoItems = [
40+
{
41+
title: 'Main dashboard - first login tour',
42+
timestamp: '10:00 AM',
43+
idItem: '12548',
44+
text: 'This pops up the first time the user logins to the dashboard.',
45+
onDelete: () => { },
46+
onEdit: () => { }
47+
},
48+
];
49+
50+
return (
51+
<div className="product-page-container">
52+
<div className="product-page-header">
53+
<ContentHeader title={showDemoItems ? "Demo Tours" : "All Tours"} />
54+
<Button text="Create a new tour" variant="contained" className="button-primary create-tour-button" />
55+
</div>
56+
<div className="product-page">
57+
<ContentArea className="content-area">
58+
<List items={showDemoItems ? demoItems : items} onSelectItem={handleSelect} />
59+
<List items={showDemoItems ? demoItems : items} onSelectItem={handleSelect} />
60+
<List items={showDemoItems ? demoItems : items} onSelectItem={handleSelect} />
61+
</ContentArea>
62+
<div className="tour-info-container">
63+
<div className="tour-info-box">
64+
<h4>What is a product tour?</h4>
65+
<p>
66+
A product onboarding tour is a guided walkthrough or tutorial that introduces users to a new product or service.
67+
It typically occurs when a user first signs up or logs into the product.
68+
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.
69+
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.
70+
</p>
71+
</div>
72+
</div>
73+
</div>
74+
{/* <TourDescriptionText description="A product onboarding tour is a guided walkthrough or tutorial..." />
75+
<InfoTooltip text="More info here" title="What is a product tour?" /> */}
76+
<ConfirmationPopup open={isPopupOpen} onConfirm={handleDelete} onCancel={handleClosePopup} />
77+
</div>
78+
);
79+
};
80+
81+
export default TourPage;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
.product-page-container {
2+
padding: 2% 3%;
3+
}
4+
5+
.product-page-header {
6+
display: flex;
7+
justify-content: space-between;
8+
align-items: center;
9+
width: 100%;
10+
margin-bottom: 20px;
11+
}
12+
13+
.product-page {
14+
display: flex;
15+
align-items: flex-start;
16+
}
17+
18+
.content-area {
19+
flex: 2;
20+
margin-right: 20px;
21+
}
22+
23+
.tour-info-container {
24+
flex: 1;
25+
}
26+
27+
.tour-info-box {
28+
padding: 16px;
29+
border-radius: 8px;
30+
border: 1px solid var(--grey-border);
31+
}
32+
33+
.tour-info-box h4 {
34+
margin-top: 0;
35+
color: var(--main-purple);
36+
}
37+
38+
.tour-info-box p {
39+
margin-bottom: 0;
40+
color: #6b7280;
41+
}
42+
43+
.create-tour-button {
44+
padding: 8px 16px;
45+
}

0 commit comments

Comments
 (0)