Skip to content

Commit

Permalink
CSS updates to fix viewport height & refactor form (#58)
Browse files Browse the repository at this point in the history
* make bottom nav position fix

* create generic button component to refactor

* use min-h-screen and flex spacing to fix mobile issues in form

* no need for flex-1

* allow all image types and remove z-index

* update css in summary to fit mobile view better

* useResizeWindow should fire on mount

* refactor form submit to use store getter

* refactor and update csss

* update css

* add border

* update css padding
  • Loading branch information
toreylittlefield committed Sep 24, 2023
1 parent 65b2b61 commit 0d8c945
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 93 deletions.
2 changes: 1 addition & 1 deletion packages/client/lib/components/BottomNav/BottomNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const BottomNav = () => {
};

return (
<div className="text-foreground bg-background absolute bottom-0 z-[9999] grid h-16 w-full grid-cols-5 items-center justify-items-center rounded-t-2xl p-1">
<div className="text-foreground bg-background fixed bottom-0 left-0 z-[9999] grid h-16 w-full grid-cols-5 items-center justify-items-center rounded-t-2xl p-1">
{LEFT_NAV_ITEMS.map((item) => (
<BottomNavItem
key={item.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const CategoryView = () => {
};

return (
<div className="flex-1">
<>
<h2 className="mt-4 text-xl">Category of incident</h2>
<h3 className="text-lg">Please choose one category</h3>
{categoryOptions.map((option) => (
Expand All @@ -54,7 +54,7 @@ const CategoryView = () => {
>
Please provide a category
</p>
</div>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,14 @@ const PhotoView = () => {
Browse Photos
</button>
<input
onChange={handleChange}
ref={inputRef}
accept="image/*"
className="hidden"
id="photos"
multiple
name="photos"
onChange={handleChange}
ref={inputRef}
type="file"
accept=".png,.jpg,.jpeg,.webp"
capture="environment"
multiple
className="hidden"
/>
</div>
</div>
Expand All @@ -97,10 +96,11 @@ const PhotoView = () => {
alt=""
/>
<button
className="absolute right-0 top-0 px-1 py-1"
onClick={() => removePhoto(index)}
className="text-foreground absolute right-0.5 top-0.5 z-10"
type="button"
>
<SVGIcon name="xCircleIcon" />
<SVGIcon name="xCircleIcon" className="text-negative h-7 w-7" />
</button>
</div>
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ const SummaryView = () => {
<div className="flex-1">
<h2 className="mt-4 text-xl">Summary of report</h2>
<h3 className="text-md">Please confirm the details of your report</h3>
<h2 className="mt-4 text-xl">Category</h2>
<h3 className="mt-4 text-xl">Category</h3>
<div className="flex items-center">
<input type="radio" readOnly checked className="h-4 w-4" />
<label htmlFor="" className="pl-3">
{category}
</label>
</div>
<h2 className="mt-4 text-xl">Photos</h2>
<div className="flex h-[100px]">
<div className="flex flex-row flex-wrap">
{photos.length > 0 ? (
photos.map((photo, index) => (
<div key={index} className="relative m-1">
<Image
width={20}
height={20}
className="h-auto w-20 rounded-lg"
width={80}
height={80}
className="w-20 rounded-lg"
src={URL.createObjectURL(photo)}
onLoad={(e) => {
if ('src' in e.target && typeof e.target.src === 'string') {
Expand All @@ -53,10 +53,11 @@ const SummaryView = () => {
<h2 className="mt-4 text-xl">Description</h2>
<textarea
value={description}
rows={4}
className="text-foreground bg-background border-border focus:ring-primary focus:primary block w-full rounded-lg border p-2.5 shadow-md"
rows={2}
className="text-foreground bg-background border-border focus:ring-primary focus:primary block w-full resize-y rounded-lg border p-2.5 shadow-md"
placeholder="Provide a description of your report"
disabled
// allow resizing of textarea
></textarea>
<h2 className="mt-4 text-xl">Location</h2>
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const UpdateView = () => {
const markerRef = useRef(null);

return (
<div className="flex min-h-screen justify-center">
<div className="flex justify-center">
<div className="absolute top-10 z-[9999] w-11/12">
<input
type="text"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import useFormStore from '../../../../store/formStore';
import { Button } from '../../common/Button';
import { SVGIcon } from '../../common/icons/SVGIcon';
import SubmitReportForm from './SubmitReportForm.jsx';

Expand All @@ -17,16 +18,22 @@ const FormButtons = () => {

const onNextStep = (e) => {
e.preventDefault();
if (!e.target.form.checkValidity()) {
if (!e.target?.form?.checkValidity()) {
setError(true);
} else {
setStep(step + 1);
setError(false);
}
};

// If we are on the first step, we want to cancel the form
// If we are on any other step, we want to go back one step
const handleBackClick = () => {
return step === 0 ? handleCancel : () => setStep(step - 1);
};

return (
<div className="mx-8 my-2 flex w-11/12 flex-col self-center">
<div className="bg-background border-t-foreground/30 sticky bottom-0 left-0 flex w-full flex-col items-center justify-end border-t pb-4 pt-2">
<div className="text-negative mb-2 flex flex-col items-center pt-2 text-center text-xs">
<SVGIcon name="noSymbolIcon" />
<h3 className="w-full whitespace-nowrap">
Expand All @@ -38,35 +45,16 @@ const FormButtons = () => {
</h3>
) : null}
</div>
<div className="flex justify-between">
{step === 0 ? (
<button
onClick={handleCancel}
className="bg-negative text-background m-1 flex w-1/2 items-center justify-center rounded-2xl border py-1.5 text-xl"
>
Cancel
<SVGIcon name="arrowUturnLeftIcon" className="pl-1" />
</button>
) : null}
{step > 0 ? (
<button
className="bg-background text-foreground m-1 flex w-1/2 items-center justify-center rounded-2xl border py-1.5 text-xl"
onClick={() => setStep(step - 1)}
type="button"
>
Back
<SVGIcon name="arrowUturnLeftIcon" className="pl-1" />
</button>
) : null}
<div className="flex w-full max-w-xs items-center justify-center gap-x-2">
<BackOrExitButton handleClick={handleBackClick} step={step} />
{step < 4 ? (
<button
className="bg-background text-foreground m-1 flex w-1/2 items-center justify-center rounded-2xl border py-1.5 text-xl"
type="button"
onClick={onNextStep}
<Button
buttonType="neutral"
handleClick={onNextStep}
iconName="arrowUturnRightIcon"
>
Continue
<SVGIcon name="arrowUturnRightIcon" className="pl-1" />
</button>
</Button>
) : (
<SubmitReportForm />
)}
Expand All @@ -76,3 +64,15 @@ const FormButtons = () => {
};

export default FormButtons;

const BackOrExitButton = ({ handleClick, step }) => {
return (
<Button
buttonType={step === 0 ? 'negative' : 'neutral'}
handleClick={handleClick()}
iconName="arrowUturnLeftIcon"
>
{step === 0 ? 'Cancel' : 'Back'}
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -1,43 +1,30 @@
import useFormStore from '../../../../store/formStore';
import { useMainStoreActions } from '../../../../store/store';
import { SVGIcon } from '../../common/icons/SVGIcon';
import { Button } from '../../common/Button';

const SubmitReportForm = () => {
const setShowForm = useFormStore((state) => state.setShowForm);
const resetForm = useFormStore((state) => state.resetForm);
const category = useFormStore((state) => state.category);
const photos = useFormStore((state) => state.photos);
const title = useFormStore((state) => state.title);
const description = useFormStore((state) => state.description);
const location = useFormStore((state) => state.location);
const { setMarkers } = useMainStoreActions();
const getFormData = useFormStore((state) => state.getFormData);
const resetForm = useFormStore((state) => state.resetForm);
const setShowForm = useFormStore((state) => state.setShowForm);

const handleSubmit = (category, photos, title, description, location) => {
const formObj = {
id: Date.now(),
category: category,
photos: photos,
title: title,
description: description,
location: location,
};

const handleSubmit = (e) => {
e.preventDefault();
const formObj = getFormData();
setMarkers(formObj);
setShowForm(false);
resetForm();
};

return (
<button
onClick={(e) => {
e.preventDefault();
handleSubmit(category, photos, title, description, location);
setShowForm(false);
}}
className="bg-positive text-background m-1 flex w-1/2 items-center justify-center rounded-2xl border py-1.5 text-xl"
<Button
handleClick={handleSubmit}
iconName="checkIcon"
buttonType="positive"
type="submit"
>
Submit
<SVGIcon name="checkIcon" className="pl-1" />
</button>
</Button>
);
};

Expand Down
14 changes: 6 additions & 8 deletions packages/client/lib/components/ReportForm/ReportForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,20 @@ const ReportForm = () => {

const RenderViewFromStep = renderStepMap[step];

// step 5 is the update view (map view)
const isStepFive = step === 5;

return (
<div className="bg-background">
<form
noValidate
className={`flex min-h-screen flex-col ${step !== 5 ? 'p-2' : ''}`}
>
<form className="flex min-h-screen flex-col justify-between" noValidate>
<div className={`${isStepFive ? '' : 'px-4 py-2'}`}>
{!isStepFive && (
<h1 className="text-2xl font-medium">Report your incident</h1>
)}
<RenderViewFromStep />
</div>

{!isStepFive && <FormButtons />}
</form>
</div>
{isStepFive ? null : <FormButtons />}
</form>
);
};

Expand Down
29 changes: 29 additions & 0 deletions packages/client/lib/components/common/Button.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { SVGIcon } from './icons/SVGIcon';

const BUTTON_TYPE_CLASSES_MAP = {
neutral: 'bg-background text-foreground',
positive: 'bg-positive text-background',
negative: 'bg-negative text-background',
};

export const Button = ({
children,
handleClick,
iconName,
buttonType = 'neutral',
...rest
}) => {
const buttonClasses = BUTTON_TYPE_CLASSES_MAP[buttonType];

return (
<button
className={`flex w-full items-center justify-center rounded-2xl border px-3.5 py-2 text-xl ${buttonClasses}`}
onClick={handleClick}
type="button"
{...rest}
>
{children}
<SVGIcon name={iconName} className="pl-1" />
</button>
);
};
29 changes: 19 additions & 10 deletions packages/client/lib/hooks/useResizeWindow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,29 @@ export const useResizeWindow = () => {

useEffect(() => {
let timer = null;

const updateWindowDimensions = () => {
const innerHeight = window.innerHeight;
setWindowDimensions({
width: window.innerWidth,
height: innerHeight,
});

// set css variable for mobile browsers
let vh = innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
};

// initial call on mount
updateWindowDimensions();

// update on window resize event
window.onresize = () => {
// debounce the resize event to prevent too many re-renders
clearTimeout(timer);
timer = setTimeout(() => {
const innerHeight = window.innerHeight;
setWindowDimensions({
width: window.innerWidth,
height: innerHeight,
});

// set css variable for mobile browsers
let vh = innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}, 100);
updateWindowDimensions();
}, 16);
};
// cleanup listener
return () => {
Expand Down
13 changes: 12 additions & 1 deletion packages/client/store/formStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,25 @@ const initialState = {
title: '',
};

const useFormStore = create((set) => ({
const useFormStore = create((set, get) => ({
...initialState,
category: '',
description: '',
error: false,
location: { lat: -8.7445, lng: 115.182 },
photos: [],
resetForm: () => set(initialState),
getFormData: () => {
const { category, description, location, photos, title } = get();
return {
id: Date.now(),
category: category,
photos: photos,
title: title,
description: description,
location: location,
};
},
setCategory: (str) => set(() => ({ category: str })),
setDescription: (str) => set(() => ({ description: str })),
setError: (bool) => set(() => ({ error: bool })),
Expand Down

0 comments on commit 0d8c945

Please sign in to comment.