From f8bb4f8f5786423121a73257f3d20f0f3b9c2ad5 Mon Sep 17 00:00:00 2001 From: Edgard Zavarezzi Date: Fri, 22 Apr 2022 15:53:52 -0300 Subject: [PATCH 1/2] fix: improve services intellisense --- src/services/cookie.ts | 28 +++++++++++++++++++ src/services/local-storage.ts | 47 ++++++++++++++++++++++++++++++++ src/services/lock-body-scroll.ts | 6 ++-- src/services/orientation.ts | 6 ++-- src/services/pointer-move.ts | 6 ++-- src/services/raf.ts | 8 ++++-- src/services/resize.ts | 30 +++++++++++++------- src/services/scroll.ts | 6 ++-- src/services/visibility.ts | 8 ++++-- 9 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 src/services/cookie.ts create mode 100644 src/services/local-storage.ts diff --git a/src/services/cookie.ts b/src/services/cookie.ts new file mode 100644 index 00000000..cb051bd9 --- /dev/null +++ b/src/services/cookie.ts @@ -0,0 +1,28 @@ +import Cookies from 'js-cookie'; + +type CookieListener = (name: string, value: string | undefined) => void; + +class Service { + listeners: CookieListener[] = []; + + set = (name: string, value: string, options: Cookies.CookieAttributes = { expires: 30 }) => { + Cookies.set(name, value, options); + this.listeners.forEach((listener) => listener(name, value)); + }; + + get = (name: string) => { + return Cookies.get(name); + }; + + listen = (listener: CookieListener) => { + if (!this.listeners.includes(listener)) this.listeners.push(listener); + }; + + dismiss = (listener: CookieListener) => { + this.listeners = this.listeners.filter((l) => l !== listener); + }; +} + +const CookieService = new Service(); + +export default CookieService; diff --git a/src/services/local-storage.ts b/src/services/local-storage.ts new file mode 100644 index 00000000..5603fd1e --- /dev/null +++ b/src/services/local-storage.ts @@ -0,0 +1,47 @@ +type LocalStorageListener = (name: string, value: string | undefined) => void; + +const KEY = 'NEXTJS-BOILERPLATE'; + +class Service { + listeners: LocalStorageListener[] = []; + + set = (name: string, value: string): boolean => { + try { + if (value !== undefined) { + const serializedData = localStorage.getItem(KEY); + if (serializedData === null) { + localStorage.setItem(KEY, JSON.stringify({ [name]: value })); + } else { + localStorage.setItem(KEY, JSON.stringify({ ...JSON.parse(serializedData), [name]: value })); + } + } + this.listeners.forEach((listener) => listener(name, value)); + return true; + } catch (e) { + // no local storage (ssr or incognito mode) + return false; + } + }; + + get = (name: string): string | null => { + try { + const serializedData = localStorage.getItem(KEY); + if (!serializedData) return null; + return JSON.parse(serializedData)[name] || null; + } catch (e) { + // no local storage (ssr or incognito mode) + return null; + } + }; + + listen = (listener: LocalStorageListener) => { + if (!this.listeners.includes(listener)) this.listeners.push(listener); + }; + + dismiss = (listener: LocalStorageListener) => { + this.listeners = this.listeners.filter((l) => l !== listener); + }; +} +const LocalStorageService = new Service(); + +export default LocalStorageService; diff --git a/src/services/lock-body-scroll.ts b/src/services/lock-body-scroll.ts index 6c9b6496..557fe36a 100644 --- a/src/services/lock-body-scroll.ts +++ b/src/services/lock-body-scroll.ts @@ -6,7 +6,7 @@ import scrollPage from '@/utils/scroll-page'; /** * Lock and unlock body scroll with page position restoration */ -class LockBodyScroll { +class Service { scrollPosY = 0; isLocked = false; @@ -33,4 +33,6 @@ class LockBodyScroll { }; } -export default new LockBodyScroll(); +const LockBodyScrollService = new Service(); + +export default LockBodyScrollService; diff --git a/src/services/orientation.ts b/src/services/orientation.ts index 9c1a67f0..91b057dc 100644 --- a/src/services/orientation.ts +++ b/src/services/orientation.ts @@ -1,6 +1,6 @@ type OrientationListener = (e?: Event) => void; -class OrientationService { +class Service { listeners: OrientationListener[] = []; onOrientation = (e: Event) => { @@ -22,4 +22,6 @@ class OrientationService { }; } -export default new OrientationService(); +const OrientationService = new Service(); + +export default OrientationService; diff --git a/src/services/pointer-move.ts b/src/services/pointer-move.ts index 0d05b350..3b67247e 100644 --- a/src/services/pointer-move.ts +++ b/src/services/pointer-move.ts @@ -2,7 +2,7 @@ import { device } from '@jam3/detect'; type PointerMoveListener = (x?: number, y?: number, e?: MouseEvent | TouchEvent) => void; -class PointerMoveService { +class Service { listeners: PointerMoveListener[] = []; onMove = (e: MouseEvent | TouchEvent) => { @@ -26,4 +26,6 @@ class PointerMoveService { }; } -export default new PointerMoveService(); +const PointerMoveService = new Service(); + +export default PointerMoveService; diff --git a/src/services/raf.ts b/src/services/raf.ts index 19eb68b3..1362d928 100644 --- a/src/services/raf.ts +++ b/src/services/raf.ts @@ -1,6 +1,6 @@ -type RequestAnimationFrameListener = (delta?: number) => void; +type RequestAnimationFrameListener = ((delta?: number) => void) | ((delta: number) => void); -class RequestAnimationFrameService { +class Service { listeners: RequestAnimationFrameListener[] = []; frameId = 0; elapsed = 0; @@ -30,4 +30,6 @@ class RequestAnimationFrameService { }; } -export default new RequestAnimationFrameService(); +const RafService = new Service(); + +export default RafService; diff --git a/src/services/resize.ts b/src/services/resize.ts index 9da80ce9..5fcf4491 100644 --- a/src/services/resize.ts +++ b/src/services/resize.ts @@ -2,21 +2,28 @@ import { device } from '@jam3/detect'; type ResizeListener = (e?: Event | UIEvent) => void; -class ResizeService { +let timeout: NodeJS.Timeout; +class Service { + debounceTime = 10; // in ms listeners: ResizeListener[] = []; onResize = (e: Event | UIEvent) => { - setTimeout( - () => { - this.listeners.forEach((listener) => listener(e)); - }, - device.mobile ? 500 : 0 // some mobile browsers only update window dimensions when the rotate animation finishes - ); + clearTimeout(timeout); + + timeout = setTimeout(() => { + this.listeners.forEach((listener) => listener(e)); + if (device.mobile) { + timeout = setTimeout(() => { + this.listeners.forEach((listener) => listener(e)); + }, 500); // some mobile browsers only update window dimensions when the rotate animation finishes + } + }, this.debounceTime); }; listen = (listener: ResizeListener) => { if (!this.listeners.length) { - window.addEventListener(device.mobile ? 'orientationchange' : 'resize', this.onResize); + window.addEventListener('resize', this.onResize); + if (device.mobile) window.addEventListener('orientationchange', this.onResize); } if (!this.listeners.includes(listener)) this.listeners.push(listener); }; @@ -24,9 +31,12 @@ class ResizeService { dismiss = (listener: ResizeListener) => { this.listeners = this.listeners.filter((l) => l !== listener); if (!this.listeners.length) { - window.removeEventListener(device.mobile ? 'orientationchange' : 'resize', this.onResize); + window.removeEventListener('resize', this.onResize); + if (device.mobile) window.removeEventListener('orientationchange', this.onResize); } }; } -export default new ResizeService(); +const ResizeService = new Service(); + +export default ResizeService; diff --git a/src/services/scroll.ts b/src/services/scroll.ts index 5a8cc850..d8167ee1 100644 --- a/src/services/scroll.ts +++ b/src/services/scroll.ts @@ -1,6 +1,6 @@ type ScrollListener = (e?: Event) => void; -class ScrollService { +class Service { listeners: ScrollListener[] = []; onScroll = (e: Event) => { @@ -22,4 +22,6 @@ class ScrollService { }; } -export default new ScrollService(); +const ScrollService = new Service(); + +export default ScrollService; diff --git a/src/services/visibility.ts b/src/services/visibility.ts index 9c87ff3a..7afb5110 100644 --- a/src/services/visibility.ts +++ b/src/services/visibility.ts @@ -1,6 +1,6 @@ -type VisibilityListener = (e?: Event) => void; +type VisibilityListener = ((e: Event) => void) | ((e?: Event) => void); -class VisibilityService { +class Service { listeners: VisibilityListener[] = []; onVisibility = (e: Event) => { @@ -22,4 +22,6 @@ class VisibilityService { }; } -export default new VisibilityService(); +const VisibilityService = new Service(); + +export default VisibilityService; From 79588bd8b02d5d8b55e4283715811ad2b9a7d1d0 Mon Sep 17 00:00:00 2001 From: Edgard Zavarezzi Date: Mon, 25 Apr 2022 16:24:46 -0300 Subject: [PATCH 2/2] fix: pr review --- src/services/resize.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/services/resize.ts b/src/services/resize.ts index 5fcf4491..17a4dbb6 100644 --- a/src/services/resize.ts +++ b/src/services/resize.ts @@ -1,10 +1,11 @@ import { device } from '@jam3/detect'; +import { resizeDebounceTime } from '@/data/settings'; + type ResizeListener = (e?: Event | UIEvent) => void; let timeout: NodeJS.Timeout; class Service { - debounceTime = 10; // in ms listeners: ResizeListener[] = []; onResize = (e: Event | UIEvent) => { @@ -17,7 +18,7 @@ class Service { this.listeners.forEach((listener) => listener(e)); }, 500); // some mobile browsers only update window dimensions when the rotate animation finishes } - }, this.debounceTime); + }, resizeDebounceTime); }; listen = (listener: ResizeListener) => {