Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.VARQ2-wrapper {
font-family: Arial, sans-serif;
padding: 1rem;
max-width: 600px;
margin: 0 auto;
}

.VARQ2-label {
display: block;
margin-bottom: 0.5rem;
font-size: 1rem;
font-weight: bold;
}

.VARQ2-input-container {
position: relative;
border: 1px solid #ccc;
border-radius: 4px;
padding: 0.5rem;
transition: border-color 0.2s ease-in-out;
background-color: #fff;
}

.VARQ2-input-container.over-limit {
border-color: red;
}

.VARQ2-input-container.input-focused {
border-color: #007bff;
}

.VARQ2-input {
width: 100%;
border: none;
resize: vertical;
min-height: 40px;
font-size: 1rem;
outline: none;
padding-bottom: 1.5rem;
overflow: hidden;
}

.VARQ2-input::placeholder {
color: #aaa;
}

.VARQ2-counter-wrapper {
position: absolute;
bottom: 0.25rem;
right: 0.5rem;
font-size: 0.75rem;
color: #666;
}

/* renamed to match component logic: "isOverLimit" */
.VARQ2-char-count.over-limit {
color: red;
}

.VARQ2-error-message {
color: red;
font-size: 0.875rem;
margin-top: 0.25rem;
}

@media (min-width: 768px) {
.VARQ2-wrapper {
max-width: 900px;
}
}
1 change: 1 addition & 0 deletions civictechprojects/static/css/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@
@import "partials/AllowMarkdown";
@import "partials/RecentProjects";
@import "partials/VolunteerActivityReportingQ1";
@import "partials/VolunteerActivityReportingQ2";
@import "partials/VARFormTitle"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand this is the guidance for uncontrolled inputs, but too much functionality is being separated out of this "component". We need to wrap the functionality implemented in the Story Template, and the functionality of VolunteerActivityReportingQ2() into a single file, with the top component that just taking value as a prop. It's just about where to divide the code.

Can you pull the Template code into VolunteerActivityReportingQ2.jsx and name that VolunteerActivityReportingQ2 and then rename the current VolunteerActivityReportingQ2 to something else.

But the other thing that has to be delt with is that value could change, when new data is fetched. The line

const [value, setValue] = useState(args.value);

won't allow value to change after the initial render.
We will need to add something like

useEffect(()=>setValue(args.value),[args.value])

so that if args.value changes, the state changes.

also, args should be changed to props when implementing a component - just to match the component style.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';

// The component is 'controlled' by its parent
const VolunteerActivityReportingQ2 = ({ className = '', value, setValue, isOverLimit, onFocus, onBlur, isFocused }) => {
const charCount = value.length;

const handleChange = (e) => {
setValue(e.target.value);
};

return (
<div className={`VARQ2-wrapper ${className}`}>
<label htmlFor="volunteer-activity-summary" className="VARQ2-label">
In a few words, describe what you did during the week.
</label>
<div
className={`VARQ2-input-container
${isOverLimit ? 'over-limit' : ''}
${isFocused ? 'input-focused' : ''}`}
Copy link
Collaborator

Choose a reason for hiding this comment

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

For focus, the :focus pseudo class in the styles, and not have to create a separate state to apply a className for it. And then you won't need to mess with onBlur.

>
<textarea
id="volunteer-activity-summary"
name="volunteer_activity_summary"
className="VARQ2-input"
value={value}
onChange={handleChange}
onFocus={onFocus}
onBlur={onBlur}
placeholder="Enter text..."
rows={1}
/>
<div className="VARQ2-counter-wrapper">
<span className={`VARQ2-char-count ${isOverLimit ? 'error-color' : ''}`}>
{charCount}/150
</span>
</div>
</div>
{isOverLimit && (
<div className="VARQ2-error-message">
Please limit your response to 150 characters.
</div>
)}
</div>
);
};

VolunteerActivityReportingQ2.propTypes = {
className: PropTypes.string,
value: PropTypes.string.isRequired,
setValue: PropTypes.func.isRequired,
isOverLimit: PropTypes.bool.isRequired,
isFocused: PropTypes.bool.isRequired,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
};

export default VolunteerActivityReportingQ2;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import VolunteerActivityReportingQ1 from '../VolunteerActivityReportingQ1';


export default {
title: 'VolunteerActivityReporting/VolunteerAactivityReportingQ1',
title: 'VolunteerActivityReporting/VolunteerActivityReportingQ1',
component: VolunteerActivityReportingQ1,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useState } from 'react';
import VolunteerActivityReportingQ2 from '../VolunteerActivityReportingQ2';

export default {
title: 'VolunteerActivityReporting/Q2',
component: VolunteerActivityReportingQ2,
};

const Template = (args) => {
const [value, setValue] = useState(args.value);
const [isFocused, setIsFocused] = useState(false);

// Calculate isOverLimit based on the current value state
const isOverLimit = value.length > 150;

return (
<VolunteerActivityReportingQ2
{...args}
value={value}
setValue={setValue}
isOverLimit={isOverLimit}
isFocused={isFocused} // Pass the focus state
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
);
};

export const IdleState = Template.bind({});
IdleState.args = {
value: '',
};
IdleState.parameters = {
docs: {
description: {
story: 'Default state: empty input with no error.',
},
},
};

export const FilledState = Template.bind({});
FilledState.args = {
value: 'Worked on V16 of the screens. Presented at design team meeting, got feedback.',
};
FilledState.parameters = {
docs: {
description: {
story: 'Input is pre-filled with a valid value.',
},
},
};

export const ErrorState = Template.bind({});
ErrorState.args = {
// Use a long value to demonstrate the error state
value: 'I created a new version of the form screens, and then developed the user flow diagram. I also attended the weekly design meeting as well as a team meeting for this assignment. The assigmnment took a lot of time because I had to iterate on the designs multiple times based on feedback from the team. Overall, I am happy with the progress made this week and look forward to continuing to work on this project next week.',
};
ErrorState.parameters = {
docs: {
description: {
story: 'Displays the validation error when the character count exceeds 150.',
},
},
};
Loading