Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist
node_modules
node_modules
Button.jsx
29 changes: 29 additions & 0 deletions public/empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 8 additions & 3 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
button:not(.toggle-btn):not(.delete-btn):focus-visible {
button:not(.toggle-btn):focus-visible {
outline: solid 4px var(--color-persianblue);
outline-offset: 8px;
}
button:not(.toggle-btn):not(.delete-btn):hover {
button:not(.toggle-btn):hover {
background-color: var(--color-zinc);
color: white;
cursor: pointer;
}
button:not(.toggle-btn):not(.delete-btn):active {
button:not(.toggle-btn):active {
background-color: var(--color-persianblue);
color: white;
}
Expand All @@ -18,3 +18,8 @@ button.active {
button.active:hover {
background-color: var(--color-persianblue);
}
/* style for focus for dashboard tile link */
.dash-tile-link:focus-visible {
outline: solid 4px var(--color-persianblue);
outline-offset: 8px;
}
40 changes: 18 additions & 22 deletions src/components/Button.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// prettier-ignore-file
import { useNavigate } from 'react-router-dom';
import { tv } from 'tailwind-variants/lite';

Expand All @@ -10,39 +11,32 @@ const buttonVariants = tv({
sm: 'h-12 w-[162px] text-base font-semibold rounded-lg lg:h-14 lg:w-[220px] lg:text-xl',
md: 'h-11 w-[218px] text-base font-semibold rounded-lg lg:h-14 lg:w-[286px] lg:text-xl xl:h-16 xl:w-[327px] xl:text-2xl',
lg: 'h-11 w-[345px] text-base font-medium rounded-md lg:w-[501px]',
circ: 'h-11 w-11 text-2xl rounded-full',
xl: 'h-fit w-full md:w-[450px] text-sm sm:text-base font-medium rounded-md lg:w-[501px] 2xl:w-full p-3 justify-start',
circ: 'h-11 w-11 text-2xl rounded-full'
},
color: {
primary: 'bg-eerie text-white border-1 border-eerie',
secondary: 'bg-white text-eerie border-1 border-eerie',
gradient: 'bg-gradient-to-b from-electricgreen to-persianblue text-white',
gradient: 'bg-gradient-to-b from-electricgreen to-persianblue text-white'
},
},
// default button styles if no specified props
defaultVariants: {
size: 'sm',
color: 'primary',
color: 'primary'
},
// conditional style cases for specific prop combinations
compoundVariants: [
// remove drop shadow and lower font weight for user selection button
{
color: 'secondary',
size: 'md',
className: 'drop-shadow-none !font-normal',
className: 'drop-shadow-none !font-normal'
},
],
});

export default function Button({
size,
color,
label,
onClick,
isActive,
to,
...props
}) {
export default function Button({ size, color, label, onClick, isActive, to, title, subtitle, ...props }) {
let navigate = useNavigate();

function handleClick() {
Expand All @@ -54,16 +48,18 @@ export default function Button({
}

return (
<button
onClick={handleClick}
className={
isActive
? `${buttonVariants({ size, color })} active`
: buttonVariants({ size, color })
}
{...props}
<button
onClick={handleClick}
className={isActive ? `${buttonVariants({ size, color })} active` : buttonVariants({ size, color })} {...props}
>
{label}
{title && subtitle ? (
<div className='text-left'>
<h3 className='font-semibold'>{title}</h3>
<p>{subtitle}</p>
</div>
) : (
label
)}
</button>
);
}
34 changes: 32 additions & 2 deletions src/components/Dashboard/DashboardTile.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { tv } from "tailwind-variants/lite";
import ProgressDay from "./ProgressDay";

const tileVariants = tv({
base: 'font-poppins flex flex-col justify-start py-6 px-4 rounded-lg shadow-[0_4px_15px_rgba(0,0,0,0.25)]',
Expand All @@ -15,6 +16,7 @@ const tileVariants = tv({
type: {
regular: '',
data: '',
progress: ''
},
},
});
Expand All @@ -30,15 +32,43 @@ const imgVariants = tv({
},
});

export default function DashboardTile({ type, size, span, title, subtitle, imgSource, altText, dataSentence }){
export default function DashboardTile({ type, size, span, title, subtitle, imgSource, altText, dataSentence, progressDays, onClick, onKeyDown }){
return (
<div className={tileVariants({ type, size, span })}>
// if an onClick prop exists, set a cursor pointer, add a role of button, and make it open to tab nav
<div
className={`${tileVariants({ type, size, span })} ${onClick ? 'cursor-pointer dash-tile-link': ''}`}
onClick={onClick}
role={onClick ? 'button': undefined}
tabIndex={onClick ? 0 : undefined}
onKeyDown={onKeyDown}
>
{type == "data" ? (
<div className="h-full flex flex-col gap-8 text-left">
<h2 className="text-lg md:text-[20px] font-medium">{title}</h2>
<p className="text-3xl md:text-4xl">{dataSentence}</p>
<p className="text-base">{subtitle}</p>
</div>
) : type == "progress" ? (
<div className="h-full flex flex-col gap-2 text-center">
<h2 className="text-[20px] font-medium">{title}</h2>
<p className="text-base font-normal">{subtitle}</p>
{ progressDays.length > 0 ? (
/* div for progress map */
<div className="h-full w-full sm:w-2/3 self-center justify-evenly flex flex-col">
{ progressDays.map(day => (
<ProgressDay
// key for react render
key={day}
// pass the day prop so it'll render in component
day={day}
/>
))}
</div>
) : (
// image for empty state - no completed challenges yet
<img src={imgSource} alt={altText} className={imgVariants({ size })}/>
)}
</div>
) : (
<div className="flex flex-col gap-2 text-center">
<h2 className="text-[20px] font-medium">{title}</h2>
Expand Down
14 changes: 14 additions & 0 deletions src/components/Dashboard/ProgressDay.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FaCircle, FaCircleCheck } from "react-icons/fa6"

export default function ProgressDay({ day }) {
return (
<div className="w-full flex flex-row justify-between items-center text-xl">
<div className="flex flex-row gap-3 items-center">
<p>Journal</p>
<FaCircle className="text-[8px]"/>
<p>Day {day}</p>
</div>
<FaCircleCheck className="text-green text-xl shrink-0"/>
</div>
)
}
88 changes: 60 additions & 28 deletions src/components/Dashboard/TaskModal.jsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,107 @@
import { useEffect, useState } from 'react';
import Button from "../Button";
import { IoClose } from "react-icons/io5";
import { useNavigate } from 'react-router-dom';
import { db } from '../../firebase';
import { doc, updateDoc } from 'firebase/firestore';

export default function TaskModal({ isOpen, onClose}) {
export default function TaskModal({ isOpen, onClose, user}) {
console.log('task modal is open', isOpen);
const navigate = useNavigate();
const [selectedTask, setSelectedTask] = useState([]);

// log the selectedTask after the array changes to update automatically
useEffect(() => {
// log the selectedTask after the array changes to update automatically
useEffect(() => {
console.log('Updated Tasks:', selectedTask);
}, [selectedTask]);

function toggleTask(challenge) {
// if the clicked challenge is not selectedTask, setSelectedTask
if (!selectedTask.includes(challenge)) {
// log the selection
console.log(`${challenge} button selected!`);
setSelectedTask([...selectedTask, challenge]);
// if the clicked challenge is already in selectedTask, filter it out of selectedTask
} else {
// log the deselection
console.log(`${challenge} button deselected!`);
setSelectedTask(selectedTask.filter(item => item !== challenge));
if (!selectedTask.includes(challenge)) {
// log the selection
console.log(`${challenge} button selected!`);
setSelectedTask([...selectedTask, challenge]);
// if the clicked challenge is already in selectedTask, filter it out of selectedTask
} else {
// log the deselection
console.log(`${challenge} button deselected!`);
setSelectedTask(selectedTask.filter(item => item !== challenge));
}
}

// function to save selected tasks to firestore and local storage
async function saveTasks(){
if (!user){
console.log('User not authenticated yet')
return;
}
const userDocRef = doc(db, "users", user.uid);
try {
await updateDoc(userDocRef, {
challengesSelected: selectedTask
});

console.log("User saved these tasks:", selectedTask);

// then route to the challenges page
navigate("/challenges");
} catch (error) {
console.error("Error while saving user tasks to firestore", error);
console.log("Error sending tasks to database");
}
}
}

if (!isOpen) return null;

return (
<div className="fixed inset-0 flex justify-center items-center bg-gray-400/30 z-20">
<div className="flex flex-col justify-center items-center gap-10 p-8 h-fit rounded-[20px] bg-gradient-to-b from-nyanza to-celeste opacity-100">
<div className="fixed inset-0 flex justify-center items-center bg-gray-400/30 z-20 h-[100vh]" aria-modal="true" role='dialog' aria-labelledby='modal-title'>
<div className="flex flex-col justify-start items-center gap-3 md:gap-6 p-4 lg:p-10 lg:pb-6 max-h-full sm:max-h-[90vh] md:max-h-[95vh] lg:max-h-[100vh] xl:h-fit w-[90vw] md:w-[70vw] lg:w-[55vw] rounded-[20px] bg-gradient-to-b from-nyanza to-celeste opacity-100 overflow-y-auto">
<button onClick={onClose} className='toggle-btn place-self-start active:outline-4 active:outline-persianblue focus-visible:outline-4 focus-visible:outline-persianblue'><IoClose className='text-2xl'/></button>
<h2 className="font-poppins text-2xl font-bold">Detox Challenge Options</h2>
<h2 className="font-poppins text-base lg:text-2xl font-bold" id='modal-title'>Detox Challenge Options</h2>
{/* buttons */}
<div className="flex flex-col gap-4 text-left">
<div className="flex flex-col gap-4 md:gap-3 text-left w-full items-center">
<Button
size="lg"
size="xl"
color="secondary"
label="Practice Saying No: This task helps you set boundaries in & outside the office."
title="Practice Saying No:"
subtitle="This task helps you set boundaries in & outside the office."
onClick={() => toggleTask('Practice Saying No: This task helps you set boundaries in & outside the office.')}
isActive={selectedTask.includes('Practice Saying No: This task helps you set boundaries in & outside the office.')}
/>
<Button
size="lg"
size="xl"
color="secondary"
label="Read Positive Affirmations: Are you struggling with impostor syndrome, anxiety, & self-doubt? Then this task is for you."
title="Read Positive Affirmations:"
subtitle="Are you struggling with impostor syndrome, anxiety, & self-doubt? Then this task is for you."
onClick={() => toggleTask('Read Positive Affirmations: Are you struggling with impostor syndrome, anxiety, & self-doubt? Then this task is for you.')}
isActive={selectedTask.includes('Read Positive Affirmations: Are you struggling with impostor syndrome, anxiety, & self-doubt? Then this task is for you.')}
/>
<Button
size="lg"
size="xl"
color="secondary"
label="Read a Book: When is the last time you sat down and read a good book?"
title="Read a Book:"
subtitle="When is the last time you sat down and read a good book?"
onClick={() => toggleTask('Read a Book: When is the last time you sat down and read a good book?')}
isActive={selectedTask.includes('Read a Book: When is the last time you sat down and read a good book?')}
/>
<Button
size="lg"
size="xl"
color="secondary"
label="Sleep 7 to 9 Hours: Your quality of sleep greatly affects your emotions and ability to process information."
title="Sleep 7 to 9 Hours:"
subtitle="Your quality of sleep greatly affects your emotions and ability to process information."
onClick={() => toggleTask('Sleep 7 to 9 Hours: Your quality of sleep greatly affects your emotions and ability to process information.')}
isActive={selectedTask.includes('Sleep 7 to 9 Hours: Your quality of sleep greatly affects your emotions and ability to process information.')}
/>
<Button
size="lg"
size="xl"
color="secondary"
label="Journal Entry: Respond to journal prompts or share your thoughts and feelings each day."
title="Journal Entry:"
subtitle="Respond to journal prompts or share your thoughts and feelings each day."
onClick={() => toggleTask('Journal Entry: Respond to journal prompts or share your thoughts and feelings each day.')}
isActive={selectedTask.includes('Journal Entry: Respond to journal prompts or share your thoughts and feelings each day.')}
/>
</div>
<Button size="sm" to="/journal" label="Save" />
<div className='shrink-0'><Button size="sm" onClick={saveTasks} label="Save"/></div>
</div>
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion src/firebase.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
import { getAuth } from 'firebase/auth';
import { browserLocalPersistence, getAuth, setPersistence } from 'firebase/auth';

// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
Expand All @@ -19,6 +19,7 @@ const firebaseConfig = {
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
setPersistence(auth, browserLocalPersistence);
// Initialize Cloud Firestore and get a reference to the service
const db = getFirestore(app);
export { db, auth };
Loading