Fixed issue scrolling on mobile

This commit is contained in:
lasse 2025-05-28 12:18:13 +02:00
parent 87033d7f9a
commit 69a0872029
8 changed files with 152 additions and 14 deletions

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { brandApi } from '../services/api';
import { Brand } from '../types';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface AddBrandModalProps {
isOpen: boolean;
@ -22,6 +23,9 @@ const AddBrandModal: React.FC<AddBrandModalProps> = ({ isOpen, onClose, onBrandA
const isEditMode = !!editBrand;
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
// Initialize form data when editing
useEffect(() => {
if (editBrand) {
@ -103,8 +107,19 @@ const AddBrandModal: React.FC<AddBrandModalProps> = ({ isOpen, onClose, onBrandA
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { GroceryCategory, GroceryCategoryCreate } from '../types';
import { groceryCategoryApi } from '../services/api';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface AddGroceryCategoryModalProps {
category?: GroceryCategory | null;
@ -8,6 +9,9 @@ interface AddGroceryCategoryModalProps {
}
const AddGroceryCategoryModal: React.FC<AddGroceryCategoryModalProps> = ({ category, onClose }) => {
// Use body scroll lock when modal is open (always open when component is rendered)
useBodyScrollLock(true);
const [formData, setFormData] = useState<GroceryCategoryCreate>({
name: ''
});
@ -69,8 +73,19 @@ const AddGroceryCategoryModal: React.FC<AddGroceryCategoryModalProps> = ({ categ
};
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<h3 className="text-lg font-medium text-gray-900 mb-4">
{isEditMode ? 'Edit Category' : 'Add New Category'}

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect, useCallback } from 'react';
import { productApi, brandApi, groceryCategoryApi } from '../services/api';
import { Product, Brand, GroceryCategory } from '../types';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface AddProductModalProps {
isOpen: boolean;
@ -34,6 +35,9 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
const weightUnits = ['piece', 'g', 'kg', 'lb', 'oz', 'ml', 'l'];
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
// Fetch brands and categories when modal opens
useEffect(() => {
if (isOpen) {
@ -167,8 +171,19 @@ const AddProductModal: React.FC<AddProductModalProps> = ({ isOpen, onClose, onPr
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { shopApi, brandApi, brandInShopApi } from '../services/api';
import { Shop, Brand, BrandInShop } from '../types';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface AddShopModalProps {
isOpen: boolean;
@ -29,6 +30,9 @@ const AddShopModal: React.FC<AddShopModalProps> = ({ isOpen, onClose, onShopAdde
const isEditMode = !!editShop;
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
// Load brands when modal opens
useEffect(() => {
if (isOpen) {
@ -198,8 +202,19 @@ const AddShopModal: React.FC<AddShopModalProps> = ({ isOpen, onClose, onShopAdde
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white max-h-[80vh] overflow-y-auto">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white max-h-[80vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Shop, Product, ShoppingEventCreate, ProductInEvent, ShoppingEvent, BrandInShop } from '../types';
import { shopApi, productApi, shoppingEventApi, brandInShopApi } from '../services/api';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface AddShoppingEventModalProps {
isOpen: boolean;
@ -15,6 +16,9 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
onEventAdded,
editEvent
}) => {
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
const [shops, setShops] = useState<Shop[]>([]);
const [products, setProducts] = useState<Product[]>([]);
const [shopBrands, setShopBrands] = useState<BrandInShop[]>([]);
@ -273,8 +277,19 @@ const AddShoppingEventModal: React.FC<AddShoppingEventModalProps> = ({
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative min-h-screen md:min-h-0 md:top-10 mx-auto p-4 md:p-5 w-full md:max-w-4xl md:shadow-lg md:rounded-md bg-white">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative min-h-screen md:min-h-0 md:top-10 mx-auto p-4 md:p-5 w-full md:max-w-4xl md:shadow-lg md:rounded-md bg-white"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg md:text-xl font-medium text-gray-900">

View File

@ -1,4 +1,5 @@
import React, { useEffect } from 'react';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface ConfirmDeleteModalProps {
isOpen: boolean;
@ -17,6 +18,9 @@ const ConfirmDeleteModal: React.FC<ConfirmDeleteModalProps> = ({
message,
isLoading = false
}) => {
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
useEffect(() => {
if (!isOpen) return;
@ -38,8 +42,19 @@ const ConfirmDeleteModal: React.FC<ConfirmDeleteModalProps> = ({
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex items-center mb-4">
<div className="flex-shrink-0">

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import Papa from 'papaparse';
import { Brand, GroceryCategory, Product } from '../types';
import { brandApi, groceryCategoryApi, productApi } from '../services/api';
import { useBodyScrollLock } from '../hooks/useBodyScrollLock';
interface ImportExportModalProps {
isOpen: boolean;
@ -18,6 +19,9 @@ interface ImportResult {
}
const ImportExportModal: React.FC<ImportExportModalProps> = ({ isOpen, onClose, onDataChanged }) => {
// Use body scroll lock when modal is open
useBodyScrollLock(isOpen);
const [activeTab, setActiveTab] = useState<'export' | 'import'>('export');
const [selectedEntity, setSelectedEntity] = useState<EntityType>('brands');
const [loading, setLoading] = useState(false);
@ -338,8 +342,19 @@ const ImportExportModal: React.FC<ImportExportModalProps> = ({ isOpen, onClose,
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-10 mx-auto p-5 border w-full max-w-4xl shadow-lg rounded-md bg-white max-h-[90vh] overflow-y-auto">
<div
className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"
onClick={(e) => {
// Close modal if clicking on backdrop
if (e.target === e.currentTarget) {
onClose();
}
}}
>
<div
className="relative top-10 mx-auto p-5 border w-full max-w-4xl shadow-lg rounded-md bg-white max-h-[90vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<div className="mt-3">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">

View File

@ -0,0 +1,33 @@
import { useEffect } from 'react';
export const useBodyScrollLock = (isLocked: boolean) => {
useEffect(() => {
if (!isLocked) return;
// Store original body overflow and position
const originalOverflow = document.body.style.overflow;
const originalPosition = document.body.style.position;
const originalTop = document.body.style.top;
const originalWidth = document.body.style.width;
// Get current scroll position
const scrollY = window.scrollY;
// Lock the body scroll
document.body.style.overflow = 'hidden';
document.body.style.position = 'fixed';
document.body.style.top = `-${scrollY}px`;
document.body.style.width = '100%';
// Cleanup function to restore original styles
return () => {
document.body.style.overflow = originalOverflow;
document.body.style.position = originalPosition;
document.body.style.top = originalTop;
document.body.style.width = originalWidth;
// Restore scroll position
window.scrollTo(0, scrollY);
};
}, [isLocked]);
};