This commit is contained in:
plebeius.eth
2023-09-16 21:40:23 +02:00
parent d963c90d26
commit 020e509b71
39 changed files with 1970 additions and 2035 deletions
+22 -23
View File
@@ -1,30 +1,29 @@
import { useEffect } from "react";
import { useAccount } from "@plebbit/plebbit-react-hooks";
import useAnonModeStore from "./stores/useAnonModeStore";
import { useEffect } from 'react';
import { useAccount } from '@plebbit/plebbit-react-hooks';
import useAnonModeStore from './stores/useAnonModeStore';
const useAnonMode = (threadCid, execute) => {
const account = useAccount();
const { anonymousMode } = useAnonModeStore();
const account = useAccount();
const { anonymousMode } = useAnonModeStore();
useEffect(() => {
const handleAnonMode = async () => {
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
useEffect(() => {
const handleAnonMode = async () => {
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
if (!anonymousMode) {
if (execute && storedSigners[threadCid]) {
const signerPrivateKey = storedSigners[threadCid];
if (account) {
await account.plebbit.createSigner({type: 'ed25519', privateKey: signerPrivateKey});
}
}
}
}
if (!anonymousMode) {
if (execute && storedSigners[threadCid]) {
const signerPrivateKey = storedSigners[threadCid];
if (account) {
await account.plebbit.createSigner({ type: 'ed25519', privateKey: signerPrivateKey });
}
}
}
};
handleAnonMode();
}, [threadCid, execute, account, anonymousMode]);
handleAnonMode();
}, [threadCid, execute, account, anonymousMode]);
return;
};
return;
}
export default useAnonMode;
export default useAnonMode;
+22 -22
View File
@@ -1,28 +1,28 @@
import { useEffect } from "react";
import { useAccount } from "@plebbit/plebbit-react-hooks";
import useAnonModeStore from "./stores/useAnonModeStore";
import { useEffect } from 'react';
import { useAccount } from '@plebbit/plebbit-react-hooks';
import useAnonModeStore from './stores/useAnonModeStore';
const useAnonModeRef = (threadCidRef, execute) => {
const account = useAccount();
const { anonymousMode } = useAnonModeStore();
const account = useAccount();
const { anonymousMode } = useAnonModeStore();
useEffect(() => {
const handleAnonMode = async () => {
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
useEffect(() => {
const handleAnonMode = async () => {
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
if (!anonymousMode) {
if (execute && storedSigners[threadCidRef]) {
const signerPrivateKey = storedSigners[threadCidRef];
if (account) {
await account.plebbit.createSigner({type: 'ed25519', privateKey: signerPrivateKey});
}
}
}
}
if (!anonymousMode) {
if (execute && storedSigners[threadCidRef]) {
const signerPrivateKey = storedSigners[threadCidRef];
if (account) {
await account.plebbit.createSigner({ type: 'ed25519', privateKey: signerPrivateKey });
}
}
}
};
handleAnonMode();
}, [threadCidRef, execute, account, anonymousMode]);
handleAnonMode();
}, [threadCidRef, execute, account, anonymousMode]);
return;
}
export default useAnonModeRef;
return;
};
export default useAnonModeRef;
+8 -8
View File
@@ -1,14 +1,14 @@
import useGeneralStore from "./stores/useGeneralStore";
import useGeneralStore from './stores/useGeneralStore';
const useClickForm = () => {
const { setShowPostForm, setShowPostFormLink } = useGeneralStore.getState();
const { setShowPostForm, setShowPostFormLink } = useGeneralStore.getState();
const handleClickForm = () => {
setShowPostForm(true);
setShowPostFormLink(false);
};
const handleClickForm = () => {
setShowPostForm(true);
setShowPostFormLink(false);
};
return handleClickForm;
return handleClickForm;
};
export default useClickForm;
export default useClickForm;
+42 -43
View File
@@ -1,53 +1,52 @@
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
const useError = () => {
const [errorMessage, setErrorMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
const [errorMessage, setErrorMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
useEffect(() => {
if (errorMessage && errorMessage.length > 0) {
const showErrorToast = () => {
const toastId = toast.error(errorMessage.toString(), {
position: "top-right",
autoClose: false,
hideProgressBar: true,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: "dark",
});
useEffect(() => {
if (errorMessage && errorMessage.length > 0) {
const showErrorToast = () => {
const toastId = toast.error(errorMessage.toString(), {
position: 'top-right',
autoClose: false,
hideProgressBar: true,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: 'dark',
});
return () => {
toast.dismiss(toastId);
};
};
return () => {
toast.dismiss(toastId);
};
};
const timeoutId = setTimeout(showErrorToast, 500);
const timeoutId = setTimeout(showErrorToast, 500);
return () => {
clearTimeout(timeoutId);
};
}
}, [errorMessage, renderCount]);
return () => {
clearTimeout(timeoutId);
};
}
}, [errorMessage, renderCount]);
const setNewErrorMessage = (error) => {
let message;
if (typeof error === 'string') {
message = error;
} else if (error instanceof Error) {
message = error.message;
} else {
message = JSON.stringify(error);
}
setErrorMessage(message);
setRenderCount(prevCount => prevCount + 1);
};
const setNewErrorMessage = (error) => {
let message;
if (typeof error === 'string') {
message = error;
} else if (error instanceof Error) {
message = error.message;
} else {
message = JSON.stringify(error);
}
return [errorMessage, setNewErrorMessage];
setErrorMessage(message);
setRenderCount((prevCount) => prevCount + 1);
};
return [errorMessage, setNewErrorMessage];
};
export default useError;
export default useError;
+16 -17
View File
@@ -1,20 +1,19 @@
import { useMemo, useRef } from "react"
import { useMemo, useRef } from 'react';
const useFeedRows = (feedWithDescriptionAndRules, columnCount) => {
const rowsRef = useRef([]);
return useMemo(() => {
const rows = [];
for (let i = 0; i < feedWithDescriptionAndRules.length; i += columnCount) {
if (rowsRef.current?.[rows.length] && rowsRef.current[rows.length].length === columnCount) {
rows.push(rowsRef.current[rows.length])
}
else {
rows.push(feedWithDescriptionAndRules.slice(i, i + columnCount))
}
}
rowsRef.current = rows
return rows;
}, [feedWithDescriptionAndRules, columnCount]);
}
const rowsRef = useRef([]);
return useMemo(() => {
const rows = [];
for (let i = 0; i < feedWithDescriptionAndRules.length; i += columnCount) {
if (rowsRef.current?.[rows.length] && rowsRef.current[rows.length].length === columnCount) {
rows.push(rowsRef.current[rows.length]);
} else {
rows.push(feedWithDescriptionAndRules.slice(i, i + columnCount));
}
}
rowsRef.current = rows;
return rows;
}, [feedWithDescriptionAndRules, columnCount]);
};
export default useFeedRows;
export default useFeedRows;
+87 -88
View File
@@ -1,96 +1,95 @@
import { useMemo } from "react"
import { useMemo } from 'react';
const useFeedStateString = (subplebbits) => {
return useMemo(() => {
const getClientHost = (clientUrl) => {
try {
clientUrl = new URL(clientUrl).hostname || clientUrl
}
catch (e) {}
return clientUrl
}
const getClientUrls = (regex) => {
const clientUrls = new Set()
const addClientUrl = (client, clientUrl) => client?.state?.match?.(regex) && clientUrls.add(getClientHost(clientUrl))
for (const subplebbit of subplebbits) {
for (const clientUrl in subplebbit?.clients?.ipfsGateways) {
addClientUrl(subplebbit.clients.ipfsGateways[clientUrl], clientUrl)
}
for (const clientUrl in subplebbit?.clients?.ipfsClients) {
addClientUrl(subplebbit.clients.ipfsClients[clientUrl], clientUrl)
}
for (const chainTicker in subplebbit?.clients?.chainProviders) {
for (const clientUrl in subplebbit.clients.chainProviders[chainTicker]) {
addClientUrl(subplebbit.clients.chainProviders[chainTicker][clientUrl], clientUrl)
}
}
// find subplebbit pages states
if (subplebbit?.posts?.clients) {
for (const clientType in subplebbit.posts.clients) {
for (const sortType in subplebbit.posts.clients[clientType]) {
for (const clientUrl in subplebbit.posts.clients[clientType][sortType]) {
addClientUrl(subplebbit.posts.clients[clientType][sortType][clientUrl], clientUrl)
}
}
}
}
}
return [...clientUrls]
}
return useMemo(() => {
const getClientHost = (clientUrl) => {
try {
clientUrl = new URL(clientUrl).hostname || clientUrl;
} catch (e) {}
return clientUrl;
};
const getClientUrls = (regex) => {
const clientUrls = new Set();
const addClientUrl = (client, clientUrl) => client?.state?.match?.(regex) && clientUrls.add(getClientHost(clientUrl));
for (const subplebbit of subplebbits) {
for (const clientUrl in subplebbit?.clients?.ipfsGateways) {
addClientUrl(subplebbit.clients.ipfsGateways[clientUrl], clientUrl);
}
for (const clientUrl in subplebbit?.clients?.ipfsClients) {
addClientUrl(subplebbit.clients.ipfsClients[clientUrl], clientUrl);
}
for (const chainTicker in subplebbit?.clients?.chainProviders) {
for (const clientUrl in subplebbit.clients.chainProviders[chainTicker]) {
addClientUrl(subplebbit.clients.chainProviders[chainTicker][clientUrl], clientUrl);
}
}
// find subplebbit pages states
if (subplebbit?.posts?.clients) {
for (const clientType in subplebbit.posts.clients) {
for (const sortType in subplebbit.posts.clients[clientType]) {
for (const clientUrl in subplebbit.posts.clients[clientType][sortType]) {
addClientUrl(subplebbit.posts.clients[clientType][sortType][clientUrl], clientUrl);
}
}
}
}
}
return [...clientUrls];
};
if (!subplebbits) {
return
}
if (!subplebbits) {
return;
}
const states = {}
for (const subplebbit of subplebbits) {
states[subplebbit?.updatingState] = (states[subplebbit?.updatingState] || 0) + 1
// find subplebbit pages states
for (const clientType in subplebbit?.posts?.clients) {
for (const sortType in subplebbit.posts.clients[clientType]) {
for (const clientUrl in subplebbit.posts.clients[clientType][sortType]) {
const state = subplebbit.posts.clients[clientType][sortType][clientUrl].state
states[state] = (states[state] || 0) + 1
}
}
}
}
const states = {};
for (const subplebbit of subplebbits) {
states[subplebbit?.updatingState] = (states[subplebbit?.updatingState] || 0) + 1;
// find subplebbit pages states
for (const clientType in subplebbit?.posts?.clients) {
for (const sortType in subplebbit.posts.clients[clientType]) {
for (const clientUrl in subplebbit.posts.clients[clientType][sortType]) {
const state = subplebbit.posts.clients[clientType][sortType][clientUrl].state;
states[state] = (states[state] || 0) + 1;
}
}
}
}
// e.g. Resolving 2 addresses from infura.io, fetching 2 IPNS, 1 IPFS from cloudflare-ipfs.com, ipfs.io
let stateString = ''
if (states['resolving-address']) {
stateString += `resolving ${states['resolving-address']} addresses`
const clientUrls = getClientUrls(/address/)
if (clientUrls.length) {
stateString += ` from ${clientUrls.join(', ')}`
}
}
if (states['fetching-ipns'] || states['fetching-ipfs']) {
if (stateString) {
stateString += ', '
}
stateString += `fetching `
if (states['fetching-ipns']) {
stateString += `${states['fetching-ipns']} IPNS`
}
if (states['fetching-ipfs']) {
if (states['fetching-ipns']) {
stateString += ', '
}
stateString += `${states['fetching-ipfs']} IPFS`
}
const clientUrls = getClientUrls(/ipfs|ipns/)
if (clientUrls.length) {
stateString += ` from ${clientUrls.join(', ')}`
}
}
// e.g. Resolving 2 addresses from infura.io, fetching 2 IPNS, 1 IPFS from cloudflare-ipfs.com, ipfs.io
let stateString = '';
if (states['resolving-address']) {
stateString += `resolving ${states['resolving-address']} addresses`;
const clientUrls = getClientUrls(/address/);
if (clientUrls.length) {
stateString += ` from ${clientUrls.join(', ')}`;
}
}
if (states['fetching-ipns'] || states['fetching-ipfs']) {
if (stateString) {
stateString += ', ';
}
stateString += `fetching `;
if (states['fetching-ipns']) {
stateString += `${states['fetching-ipns']} IPNS`;
}
if (states['fetching-ipfs']) {
if (states['fetching-ipns']) {
stateString += ', ';
}
stateString += `${states['fetching-ipfs']} IPFS`;
}
const clientUrls = getClientUrls(/ipfs|ipns/);
if (clientUrls.length) {
stateString += ` from ${clientUrls.join(', ')}`;
}
}
// capitalize first letter
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1)
// capitalize first letter
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1);
// if string is empty, return undefined instead
return stateString || undefined
}, [subplebbits])
}
// if string is empty, return undefined instead
return stateString || undefined;
}, [subplebbits]);
};
export default useFeedStateString
export default useFeedStateString;
+34 -34
View File
@@ -1,43 +1,43 @@
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
const useInfo = () => {
const [infoMessage, setInfoMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
useEffect(() => {
if (infoMessage && infoMessage.length > 0) {
const showInfoToast = () => {
const toastId = toast.info(infoMessage.toString(), {
position: "top-right",
autoClose: false,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: "dark",
});
const [infoMessage, setInfoMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
return () => {
toast.dismiss(toastId);
};
};
useEffect(() => {
if (infoMessage && infoMessage.length > 0) {
const showInfoToast = () => {
const toastId = toast.info(infoMessage.toString(), {
position: 'top-right',
autoClose: false,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: 'dark',
});
const timeoutId = setTimeout(showInfoToast, 500);
return () => {
toast.dismiss(toastId);
};
};
return () => {
clearTimeout(timeoutId);
};
}
}, [infoMessage, renderCount]);
const timeoutId = setTimeout(showInfoToast, 500);
const setNewInfoMessage = (message) => {
setInfoMessage(message);
setRenderCount(prevCount => prevCount + 1);
};
return () => {
clearTimeout(timeoutId);
};
}
}, [infoMessage, renderCount]);
return [infoMessage, setNewInfoMessage];
const setNewInfoMessage = (message) => {
setInfoMessage(message);
setRenderCount((prevCount) => prevCount + 1);
};
return [infoMessage, setNewInfoMessage];
};
export default useInfo;
export default useInfo;
+94 -96
View File
@@ -1,110 +1,108 @@
import { useMemo } from 'react'
import { useMemo } from 'react';
const useStateString = (commentOrSubplebbit) => {
return useMemo(() => {
// dont show state string if the data is already fetched
if (commentOrSubplebbit?.updatedAt || commentOrSubplebbit?.state === 'succeeded') {
return
}
return useMemo(() => {
// dont show state string if the data is already fetched
if (commentOrSubplebbit?.updatedAt || commentOrSubplebbit?.state === 'succeeded') {
return;
}
if (!commentOrSubplebbit?.clients) {
return
}
const clients = commentOrSubplebbit?.clients
if (!commentOrSubplebbit?.clients) {
return;
}
const clients = commentOrSubplebbit?.clients;
const states = {}
const addState = (state, clientUrl) => {
if (!state || state === 'stopped') {
return
}
if (!states[state]) {
states[state] = []
}
states[state].push(clientUrl)
}
for (const clientUrl in clients?.ipfsGateways) {
addState(clients.ipfsGateways[clientUrl]?.state, clientUrl)
}
for (const clientUrl in clients?.ipfsClients) {
addState(clients.ipfsClients[clientUrl]?.state, clientUrl)
}
for (const clientUrl in clients?.pubsubClients) {
addState(clients.pubsubClients[clientUrl]?.state, clientUrl)
}
for (const chainTicker in clients?.chainProviders) {
for (const clientUrl in clients.chainProviders[chainTicker]) {
addState(clients.chainProviders[chainTicker][clientUrl]?.state, clientUrl)
}
}
const states = {};
const addState = (state, clientUrl) => {
if (!state || state === 'stopped') {
return;
}
if (!states[state]) {
states[state] = [];
}
states[state].push(clientUrl);
};
for (const clientUrl in clients?.ipfsGateways) {
addState(clients.ipfsGateways[clientUrl]?.state, clientUrl);
}
for (const clientUrl in clients?.ipfsClients) {
addState(clients.ipfsClients[clientUrl]?.state, clientUrl);
}
for (const clientUrl in clients?.pubsubClients) {
addState(clients.pubsubClients[clientUrl]?.state, clientUrl);
}
for (const chainTicker in clients?.chainProviders) {
for (const clientUrl in clients.chainProviders[chainTicker]) {
addState(clients.chainProviders[chainTicker][clientUrl]?.state, clientUrl);
}
}
// find subplebbit pages states
if (commentOrSubplebbit?.posts?.clients) {
for (const clientType in commentOrSubplebbit.posts.clients) {
for (const sortType in commentOrSubplebbit.posts.clients[clientType]) {
for (const clientUrl in commentOrSubplebbit.posts.clients[clientType][sortType]) {
let state = commentOrSubplebbit.posts.clients[clientType][sortType][clientUrl].state
if (state === 'stopped') {
continue
}
state += `-page-${sortType}`
if (!states[state]) {
states[state] = []
}
states[state].push(clientUrl)
}
}
}
}
// find subplebbit pages states
if (commentOrSubplebbit?.posts?.clients) {
for (const clientType in commentOrSubplebbit.posts.clients) {
for (const sortType in commentOrSubplebbit.posts.clients[clientType]) {
for (const clientUrl in commentOrSubplebbit.posts.clients[clientType][sortType]) {
let state = commentOrSubplebbit.posts.clients[clientType][sortType][clientUrl].state;
if (state === 'stopped') {
continue;
}
state += `-page-${sortType}`;
if (!states[state]) {
states[state] = [];
}
states[state].push(clientUrl);
}
}
}
}
const getClientHost = (clientUrl) => {
try {
clientUrl = new URL(clientUrl).hostname || clientUrl
}
catch (e) {}
return clientUrl
}
const getClientHost = (clientUrl) => {
try {
clientUrl = new URL(clientUrl).hostname || clientUrl;
} catch (e) {}
return clientUrl;
};
let stateString = ''
for (const state in states) {
const clientUrls = states[state]
const clientHosts = clientUrls.map(clientUrl => getClientHost(clientUrl))
let stateString = '';
for (const state in states) {
const clientUrls = states[state];
const clientHosts = clientUrls.map((clientUrl) => getClientHost(clientUrl));
// if there are no valid hosts, skip this state
if (clientHosts.length === 0) {
continue
}
// if there are no valid hosts, skip this state
if (clientHosts.length === 0) {
continue;
}
// separate 2 different states using ', '
if (stateString) {
stateString += ', '
}
// separate 2 different states using ', '
if (stateString) {
stateString += ', ';
}
// e.g. 'fetching IPFS from cloudflare-ipfs.com, ipfs.io'
const formattedState = state.replaceAll('-', ' ').replace('ipfs', 'IPFS').replace('ipns', 'IPNS')
stateString += `${formattedState} from ${clientHosts.join(', ')}`
}
// e.g. 'fetching IPFS from cloudflare-ipfs.com, ipfs.io'
const formattedState = state.replaceAll('-', ' ').replace('ipfs', 'IPFS').replace('ipns', 'IPNS');
stateString += `${formattedState} from ${clientHosts.join(', ')}`;
}
// fallback to comment or subplebbit state when possible
if (!stateString) {
if (commentOrSubplebbit?.publishingState && commentOrSubplebbit?.publishingState !== 'stopped' && commentOrSubplebbit?.publishingState !== 'succeeded') {
stateString = commentOrSubplebbit.publishingState
}
else if (commentOrSubplebbit?.updatingState !== 'stopped' && commentOrSubplebbit?.updatingState !== 'succeeded') {
stateString = commentOrSubplebbit.updatingState
}
if (stateString) {
stateString = stateString.replaceAll('-', ' ').replace('ipfs', 'IPFS').replace('ipns', 'IPNS')
}
}
// fallback to comment or subplebbit state when possible
if (!stateString) {
if (commentOrSubplebbit?.publishingState && commentOrSubplebbit?.publishingState !== 'stopped' && commentOrSubplebbit?.publishingState !== 'succeeded') {
stateString = commentOrSubplebbit.publishingState;
} else if (commentOrSubplebbit?.updatingState !== 'stopped' && commentOrSubplebbit?.updatingState !== 'succeeded') {
stateString = commentOrSubplebbit.updatingState;
}
if (stateString) {
stateString = stateString.replaceAll('-', ' ').replace('ipfs', 'IPFS').replace('ipns', 'IPNS');
}
}
// capitalize first letter
if (stateString) {
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1)
}
// capitalize first letter
if (stateString) {
stateString = stateString.charAt(0).toUpperCase() + stateString.slice(1);
}
// if string is empty, return undefined instead
return stateString === '' ? undefined : stateString
}, [commentOrSubplebbit])
}
// if string is empty, return undefined instead
return stateString === '' ? undefined : stateString;
}, [commentOrSubplebbit]);
};
export default useStateString
export default useStateString;
+34 -34
View File
@@ -1,43 +1,43 @@
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
import { useEffect, useState } from 'react';
import { toast } from 'react-toastify';
const useSuccess = () => {
const [successMessage, setSuccessMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
useEffect(() => {
if (successMessage && successMessage.length > 0) {
const showSuccessToast = () => {
const toastId = toast.success(successMessage.toString(), {
position: "top-right",
autoClose: 3000,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: "dark",
});
const [successMessage, setSuccessMessage] = useState('');
const [renderCount, setRenderCount] = useState(0);
return () => {
toast.dismiss(toastId);
};
};
useEffect(() => {
if (successMessage && successMessage.length > 0) {
const showSuccessToast = () => {
const toastId = toast.success(successMessage.toString(), {
position: 'top-right',
autoClose: 3000,
hideProgressBar: false,
closeOnClick: false,
pauseOnHover: false,
draggable: false,
progress: undefined,
theme: 'dark',
});
const timeoutId = setTimeout(showSuccessToast, 500);
return () => {
toast.dismiss(toastId);
};
};
return () => {
clearTimeout(timeoutId);
};
}
}, [successMessage, renderCount]);
const timeoutId = setTimeout(showSuccessToast, 500);
const setNewSuccessMessage = (message) => {
setSuccessMessage(message);
setRenderCount(prevCount => prevCount + 1);
};
return () => {
clearTimeout(timeoutId);
};
}
}, [successMessage, renderCount]);
return [successMessage, setNewSuccessMessage];
const setNewSuccessMessage = (message) => {
setSuccessMessage(message);
setRenderCount((prevCount) => prevCount + 1);
};
return [successMessage, setNewSuccessMessage];
};
export default useSuccess;
export default useSuccess;
+11 -11
View File
@@ -1,16 +1,16 @@
import { useState, useEffect } from 'react'
import { useState, useEffect } from 'react';
export default function useWindowWidth() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth)
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
function handleResize() {
setWindowWidth(window.innerWidth)
}
useEffect(() => {
function handleResize() {
setWindowWidth(window.innerWidth);
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowWidth
}
return windowWidth;
}