-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement useSession for managing web sessions
- Loading branch information
Ala
committed
Jun 11, 2024
1 parent
3110746
commit 9d556a9
Showing
2 changed files
with
231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { checkItem, getCurrentSession, useSession } from '../use-session' | ||
import { renderHook, waitFor } from '@testing-library/react' | ||
import { act } from 'react' | ||
|
||
describe('useSessionStorage', () => { | ||
beforeAll(() => { | ||
localStorage.clear() | ||
}) | ||
|
||
it('should clear the session storage', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
act(() => result.current.clearsessionStorage()) | ||
|
||
expect(result.current.session.length).toBe(0) | ||
}) | ||
|
||
it('should return session storage items after first call', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
expect(result.current.session).toEqual(getCurrentSession()) | ||
}) | ||
|
||
it('should return an item or undefined', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
const item = result.current.getValue('lib') | ||
|
||
if (item) { | ||
expect(item).toBe('rehook') | ||
} else { | ||
expect(item).toBeNull() | ||
} | ||
}) | ||
|
||
it('should rename the old key to the new key', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
act(() => result.current.addItem('name', 'alaeddine')) | ||
|
||
act(() => result.current.renameKey('name', 'firstname')) | ||
|
||
expect(result.current.getValue('firstname')).not.toBeNull() | ||
}) | ||
|
||
it('should delete the item', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
act(() => result.current.addItem('age', 30)) | ||
|
||
act(() => result.current.deleteItem('age')) | ||
|
||
expect(localStorage.getItem('age')).toBeNull() | ||
}) | ||
|
||
it('should delete the item after 2 seconds', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
act(() => result.current.addItem('age', '30')) | ||
|
||
act(() => result.current.deleteItemAfterDelay('age', 2000)) | ||
|
||
waitFor(() => expect(localStorage.getItem('age')).toBeNull()) | ||
}) | ||
|
||
it('should return the the exact values or undefined', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
act(() => | ||
result.current.addMultipleItems([ | ||
{ key: 'lib', value: 'rehook' }, | ||
{ key: 'creator', value: 'alaeddine' }, | ||
]), | ||
) | ||
|
||
const items = result.current.getMultipleValues(['lib', 'creator']) | ||
|
||
expect(items.length).toBe(2) | ||
|
||
expect(checkItem('lib')).toBe('rehook') | ||
|
||
expect(checkItem('creator')).toBe('alaeddine') | ||
}) | ||
|
||
it('should add a new item or throws an error if it is exist', () => { | ||
const { result } = renderHook(() => useSession()) | ||
|
||
const item = result.current.getValue('lib') | ||
|
||
if (item !== null) { | ||
act(() => { | ||
result.current.addItem('lib', 'rehook') | ||
}) | ||
|
||
expect(item).toBe('rehook') | ||
} | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { useEffect, useState } from 'react' | ||
|
||
export type Item = string | number | object | null | ||
|
||
export const useSession = (fn?: () => void) => { | ||
const items = getCurrentSession() | ||
|
||
const [session, setSession] = useState<{ [x: string]: Item }[]>(items) | ||
|
||
useEffect(() => { | ||
if (fn && typeof fn == 'function') { | ||
fn() | ||
} | ||
}, [session, fn]) | ||
|
||
const getValue = (itemKey: string) => { | ||
const items = Object.values(session) | ||
|
||
for (const item of items) { | ||
if (itemKey in item) { | ||
return item[itemKey] | ||
} | ||
} | ||
|
||
return null | ||
} | ||
|
||
const renameKey = (oldKey: string, newKey: string) => { | ||
const item = checkItem(oldKey) | ||
|
||
if (!item) { | ||
throw new Error('This item does not exist in the session storage') | ||
} | ||
|
||
const value = sessionStorage.getItem(oldKey) | ||
|
||
sessionStorage.removeItem(oldKey) | ||
|
||
if (value) { | ||
sessionStorage.setItem(newKey, value) | ||
setSession(getCurrentSession()) | ||
} | ||
} | ||
|
||
const getMultipleValues = (keys: string[]) => { | ||
const multipleValues: string[] = [] | ||
|
||
keys.forEach(key => { | ||
const value = getValue(key) as string | ||
multipleValues.push(value) | ||
}) | ||
|
||
return multipleValues | ||
} | ||
|
||
const addItem = (key: string, value: Item) => { | ||
if (typeof value === 'object') { | ||
sessionStorage.setItem(key, JSON.stringify(value)) | ||
} | ||
|
||
if (typeof value === 'number') { | ||
sessionStorage.setItem(key, value.toString()) | ||
} | ||
|
||
if (typeof value === 'string') { | ||
sessionStorage.setItem(key, value) | ||
} | ||
|
||
setSession([...session, { [key]: value }]) | ||
} | ||
|
||
const addMultipleItems = (items: { key: string; value: string }[]) => { | ||
for (const item of items) { | ||
addItem(item.key, item.value) | ||
} | ||
} | ||
|
||
const deleteItem = (key: string) => { | ||
const item = checkItem(key) | ||
if (!item) { | ||
throw new Error('This item does not exist in the session storage') | ||
} | ||
|
||
if (item) { | ||
sessionStorage.removeItem(key) | ||
setSession(getCurrentSession()) | ||
} | ||
} | ||
|
||
const deleteItemAfterDelay = (key: string, time: number) => { | ||
setTimeout(() => { | ||
deleteItem(key) | ||
}, time) | ||
} | ||
|
||
const deleteMultipleItems = (keys: string[]) => { | ||
keys.forEach(key => { | ||
deleteItem(key) | ||
}) | ||
} | ||
|
||
const clearsessionStorage = () => { | ||
sessionStorage.clear() | ||
setSession([]) | ||
} | ||
|
||
return { | ||
session, | ||
getValue, | ||
getMultipleValues, | ||
addItem, | ||
addMultipleItems, | ||
renameKey, | ||
deleteItem, | ||
deleteItemAfterDelay, | ||
deleteMultipleItems, | ||
clearsessionStorage, | ||
} | ||
} | ||
|
||
export const checkItem = (key: string) => sessionStorage.getItem(key) | ||
|
||
export const getCurrentSession = () => { | ||
const items: { [x: string]: string | null }[] = [] | ||
|
||
const keys = Object.keys(sessionStorage) | ||
|
||
keys.forEach(key => { | ||
items.push({ [key]: sessionStorage.getItem(key) }) | ||
}) | ||
|
||
return items | ||
} |