Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Happiness survey by Joyce & Helene #84

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f6958b9
Created basic flow for survey app.
HeleneWestrin Oct 15, 2024
844e692
Updated ReadMe
HeleneWestrin Oct 15, 2024
ac078ad
Created color variables. Added custom font. Created button styling.
HeleneWestrin Oct 15, 2024
560b282
Added controlled forms for each step
HeleneWestrin Oct 15, 2024
2146c74
Added useful comments
HeleneWestrin Oct 15, 2024
c9db27b
Add progress indicator logic with circle classes and create progressI…
JoyceKuode Oct 16, 2024
e602c20
Add image, title, and paragraph to Home
JoyceKuode Oct 16, 2024
1e3a604
Created SurveyHero. Updated layout and styling for steps. Styled inputs.
HeleneWestrin Oct 16, 2024
d103193
Fixed some styling
HeleneWestrin Oct 16, 2024
25764fa
Created logic for button to be disabled if question is not answered.
HeleneWestrin Oct 16, 2024
47ed1ea
Style home page and add image to results
JoyceKuode Oct 17, 2024
5020241
Create logic to show error message if user tries to click disabled bu…
JoyceKuode Oct 17, 2024
67ff909
Add function to clear answers when user clicks Start Over button
JoyceKuode Oct 17, 2024
19dfd4c
Created styling for radio buttons. Updated the survey questions.
HeleneWestrin Oct 18, 2024
039a488
Made radio buttons more accessible
HeleneWestrin Oct 18, 2024
27e942e
Created RadioButtonGroup component to make code more DRY
HeleneWestrin Oct 18, 2024
4dc3a40
Updated ReadMe
HeleneWestrin Oct 18, 2024
e70fee7
Updated font-face name for SemiBold font
HeleneWestrin Oct 18, 2024
8df8824
Added some accessibilty features, like screen readers getting re-focu…
HeleneWestrin Oct 18, 2024
9e237f6
Updated results sentece to be lowercase
HeleneWestrin Oct 18, 2024
2fd5850
Added width and height on images to avoid layout shifts
HeleneWestrin Oct 18, 2024
0fda74b
Add details to README
JoyceKuode Oct 20, 2024
64efc11
Fixed bug with radio button not being properly checked when using the…
HeleneWestrin Oct 21, 2024
75f4103
Merge branch 'main' of https://github.com/HeleneWestrin/project-surve…
HeleneWestrin Oct 21, 2024
cbdd1c2
Polished the error message and moved it closer to the form
HeleneWestrin Oct 25, 2024
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
23 changes: 12 additions & 11 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
settings: { react: { version: "18.2" } },
plugins: ["react-refresh"],
rules: {
'react-refresh/only-export-components': [
'warn',
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
"react/prop-types": "off",
},
}
};
35 changes: 10 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,22 @@
<h1 align="center">
<a href="">
<img src="/src/assets/survey.svg" alt="Project Banner Image">
</a>
</h1>

# Survey Project

Replace this readme with your own information about your project.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.

## Getting Started with the Project

### Dependency Installation & Startup Development Server
The project involved building a React survey with at least three questions, using different input types (radio buttons, dropdown). Upon submission, users are shown a summary of their answers. The focus was on practicing React state and controlled forms while ensuring accessibility, responsiveness, and clean code.

Once cloned, navigate to the project's root directory and this project uses npm (Node Package Manager) to manage its dependencies.
Collaboration was done via GitHub and we worked on separate branches and then merged the changes to main.

The command below is a combination of installing dependencies, opening up the project on VS Code and it will run a development server on your terminal.
### The Process

```bash
npm i && code . && npm run dev
```
Prior to our first meeting, Helene set up the design on Figma and also created a flowchart to help us visualize the data flow and state management for our application.

### The Problem
We started with setting up the structure of the project by pair programming using LiveShare and a Slack huddle. When that was done, we had a semi-working flow with state manangement. We could then divide the tasks between us.

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
One challenge was that our schedules rarely aligned, so after our first meeting we had to find a way to make progress in our own time while avoiding merge conflicts. We set up a Canvas in Slack with an organized to-do list and assigned ourselves various tasks throughout the week. We also included detailed comments in our code and this helped to promote clarity and communication.

### View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
[View it live »](https://happiness-survey.netlify.app/)

## Instructions
### Collaborators

<a href="instructions.md">
See instructions of this project
</a>
Helene Westrin
Joyce Kuo
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="./src/assets/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Survey - Project - Week 6</title>
<title>Happiness survey by Joyce & Helene</title>
</head>
<body>
<div id="root"></div>
Expand Down
11 changes: 9 additions & 2 deletions instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ You don't have to use a lot of components to start with when doing this project.
How you design your page is up to you, but take accessibility into account when you are styling your form elements - so inputs should have labels and should be easily readable and usable. We STRONGLY recommend having some kind of design or sketch before starting to code.

## How to get started

1. **Person A** forks the repo
2. **Person A** invites person B as a collaborator to the repo (Settings -> Collaborators and teams -> Add people)
3. **Person A** clones the repo
Expand All @@ -24,6 +25,7 @@ How you design your page is up to you, but take accessibility into account when
7. When you're done with a feature, it's time to merge! You choose if you want to work with PRs and code reviews or if you want to do this more verbally before you merge.

## Requirements:

- Your app should consist of at least 3 questions.
- At least one question should use radio buttons.
- At least one question should use a select dropdown.
Expand All @@ -37,31 +39,35 @@ How you design your page is up to you, but take accessibility into account when
- Make your app responsive (it should look good on devices from 320px width up to 1600px)

## Stretch goals

So you’ve completed the requirements? Great job! Ensure you've committed and pushed a version of your project before starting on the stretch goals. Remember that the stretch goals are optional.

### Intermediate Stretch Goals

- Use a form element you haven't tried before (such as a [range slider](https://www.w3schools.com/howto/howto_js_rangeslider.asp)) and connect it to React state. You can find a list of input types [here](https://www.w3schools.com/html/html_form_input_types.asp).
- Add validation to your survey! Use either HTML input validation attributes (such as `required`) or implement custom logic when the user clicks the submit button to make the form fields have validations. If you choose to implement your own validation, you should also make sure to show error messages in a nice way.
- Create a button that, when clicked, will scroll down to the top of the next question in the survey (if possible)

### Advanced Stretch Goals

- Visualize to the user how far through the survey they are and how much is left by creating a progress bar
- Use Regex validation for some input on your survey
- Show different questions depending on the answer to a specific question
- Create a multi-step form. Example 👇
Show each question on its own 'page' with a continue button to progress to the next question (like how typeform does it). If you decide to split your form into sections, then one approach you could take is to try to think of these sections as a single `useState` hook which you can use to conditionally render different groups of inputs. For example, you could have some state like `const [section, setSection] = useState('firstQuestion')` and then when the user presses a button to progress, you'd use the `setSection()` function to progress them to the second question, etc. Then, in your JSX, you could conditionally render, like this:

```
const Example = () => {
const [section, setSection] = useState('firstQuestion')

return (
<div>
{section === 'firstQuestion' && (
<div>
First question...
</div>
)}

{section === 'secondQuestion' && (
<div>
Second question...
Expand All @@ -71,4 +77,5 @@ So you’ve completed the requirements? Great job! Ensure you've committed and p
)
}
```

As always, there are many ways to approach this! This is just one suggestion.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-aria-components": "^1.4.1",
"react-dom": "^18.2.0",
"vite-plugin-svgr": "^4.2.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
Expand Down
1 change: 0 additions & 1 deletion public/vite.svg

This file was deleted.

52 changes: 51 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
import { useState } from "react";
import { Home } from "./components/Home";
import { Survey } from "./components/Survey";
import { Results } from "./components/Results";

export const App = () => {
return <div>Find me in src/app.jsx!</div>;
const [surveyStarted, setSurveyStarted] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const [userAnswers, setUserAnswers] = useState({
answer1: "",
answer2: "",
answer3: "",
});

const handleSurveySubmit = (event) => {
event.preventDefault();
setCurrentStep(-1); //Switch to results
};

// Function to clear answers and start over
const resetSurvey = () => {
setSurveyStarted(false);
setCurrentStep(1);
setUserAnswers({
answer1: "",
answer2: "",
answer3: "",
});
};

return (
<>
{!surveyStarted ? (
<Home setSurveyStarted={setSurveyStarted} />
) : currentStep === -1 ? (
<Results
setSurveyStarted={setSurveyStarted}
setCurrentStep={setCurrentStep}
userAnswers={userAnswers}
resetSurvey={resetSurvey} // Pass reset function to Results
/>
) : (
<Survey
currentStep={currentStep}
setCurrentStep={setCurrentStep}
userAnswers={userAnswers}
setUserAnswers={setUserAnswers}
onSubmit={handleSurveySubmit}
/>
)}
</>
);
};
8 changes: 8 additions & 0 deletions src/assets/arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/assets/checkmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/fonts/FamiljenGrotesk-Bold.eot
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Bold.ttf
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Bold.woff
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Bold.woff2
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Regular.eot
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Regular.ttf
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Regular.woff
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-Regular.woff2
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-SemiBold.eot
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-SemiBold.ttf
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-SemiBold.woff
Binary file not shown.
Binary file added src/assets/fonts/FamiljenGrotesk-SemiBold.woff2
Binary file not shown.
Binary file added src/assets/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/results.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/components/Home.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Button } from "./ui/Button";
import homeImage from "../assets/home.png";

export const Home = ({ setSurveyStarted }) => {
return (
<main className="main-container">
<img
width="400"
height="400"
Comment on lines +8 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come you put width and height here instead of a css file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having width and height explicitly set on images (even if you control the size with CSS in some other way) prevents layout shifts when the page os loading because you preserve space for them. Especially noticeable on a slow 4G net for example. @JennieDalgren

src={homeImage}
alt="Cartoon of a person relaxed and sleeping on the sofa with abstract shapes in the background"
/>
<h1>The Science of Happiness</h1>
<p>Everyday Joy Boosters Survey</p>
<Button onClick={() => setSurveyStarted(true)} text="Let's begin!" />
</main>
);
};
35 changes: 35 additions & 0 deletions src/components/ProgressIndicator.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.progress-indicator {
display: flex;
justify-content: center;
gap: 1.75rem;
}

.circle {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: var(--pink-dark);
border: 2px solid var(--pink-dark);
font-size: 1.5rem; /* 24 (font-size you are aiming for) divided by 16 (default root font size) = 1.5 */
font-weight: 700;

span {
position: relative;
top: -2px;
}

svg {
fill: var(--blue-dark);
position: relative;
top: 5px;
}
}

.circle.active,
.circle.completed {
background-color: var(--pink-dark);
color: var(--blue-dark);
}
45 changes: 45 additions & 0 deletions src/components/ProgressIndicator.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import "./ProgressIndicator.css";
import Checkmark from "../assets/checkmark.svg?react";

export const ProgressIndicator = ({ currentStep }) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

// Function that determines which CSS class to apply to each circle based on current step
const getCircleClass = (step) => {
if (step < currentStep) return "completed";
if (step === currentStep) return "active";
return "";
};

const setAriaDisabled = (step) => {
if (step < currentStep || step > currentStep) return "true";
if (step === currentStep) return "false";
};

return (
<div className="progress-indicator">
{/* Map iterates over steps 1, 2, 3 and for each step, it calls getCircleClass(step) to determine appropriate class */}
{[1, 2, 3].map((step) => (
<div
key={step}
aria-disabled={setAriaDisabled(step)}
className={`circle ${getCircleClass(step)}`}
>
{/* If step is less than current step, it displays a checkmark, otherwise it displays the step number */}
<span>
{step < currentStep ? (
<>
<p className="sr-only">Step {step} (completed)</p>
<Checkmark />
</>
) : (
<>
<p>
<span className="sr-only">Step</span> {step}
</p>
</>
)}
</span>
</div>
))}
</div>
);
};
37 changes: 37 additions & 0 deletions src/components/Results.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Button } from "./ui/Button";

import resultsImage from "../assets/results.png";

export const Results = ({
setSurveyStarted,
setCurrentStep,
userAnswers,
resetSurvey,
}) => {
return (
<main className="main-container">
<img
width="400"
height="400"
src={resultsImage}
alt="Cartoon of a person sitting on top of a stack of oversized books and reading a book"
/>
<h1>Your results</h1>
<p>
For you, <strong>{userAnswers.answer1.toLowerCase()}</strong> is a great
way to feel happier, while{" "}
<strong>{userAnswers.answer2.toLowerCase()}</strong> can also brighten
your mood during the{" "}
<strong>{userAnswers.answer3.toLowerCase()}</strong>.
</p>
<Button
onClick={() => {
setSurveyStarted(false);
setCurrentStep(1);
resetSurvey(); // Invoke resetSurvey function
}}
text="Start Over"
/>
</main>
);
};
Loading