From 44e043b11f279e24e5a52d384b953a6e0baa47e6 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Mon, 8 Dec 2025 11:21:38 +1100 Subject: [PATCH 01/35] chore: add start option for performance metrics --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7bf069067..abc805f93 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,10 @@ "start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .", "start-prod:pretty": "yarn start-prod | pino-pretty", "start-dev": "cross-env NODE_ENV=development NODE_APP_INSTANCE=devprod$MULTI electron .", - "build": "yarn print-deps && yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:locales-soft && tsc && yarn build:workers", "start-dev:pretty": "yarn start-dev | pino-pretty", + "start-perf": "cross-env NODE_ENV=development NODE_APP_INSTANCE=devprod$MULTI electron --inspect-brk=9229 --enable-precise-memory-info --js-flags=\"--expose-gc --allow-natives-syntax\" .", + "start-dev:perf": "yarn start-perf | pino-pretty", + "build": "yarn print-deps && yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:locales-soft && tsc && yarn build:workers", "build:workers": "yarn worker:utils && yarn worker:libsession && yarn worker:image_processor", "build:locales": "python3 ./tools/localization/generateLocales.py --generate-types --print-problems --error-on-problems --error-old-dynamic-variables", "build:locales-soft": "python3 ./tools/localization/generateLocales.py --generate-types --print-problems --print-problem-strings", From 439b991fbd2df9edc0bc2bc1f45d0ed382ad639b Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Tue, 9 Dec 2025 10:59:06 +1100 Subject: [PATCH 02/35] feat: upgrade to react 19 and add babel compiler step --- babel.config.js | 175 +++ package.json | 37 +- ts/components/SessionTooltip.tsx | 5 +- ts/components/SplitViewContainer.tsx | 4 +- ts/components/basic/MessageBodyHighlight.tsx | 2 + ts/components/basic/SessionButton.tsx | 2 +- ts/components/conversation/AddMentions.tsx | 2 +- ts/components/conversation/Emojify.tsx | 2 + .../conversation/SessionConversation.tsx | 2 +- .../SessionMessagesListContainer.tsx | 2 +- .../composition/CompositionBox.tsx | 10 +- .../composition/CompositionTextArea.tsx | 8 +- .../media-gallery/AttachmentSection.tsx | 2 + .../message/message-content/MessageBody.tsx | 2 +- .../message-content/MessageContextMenu.tsx | 7 +- .../dialog/OnionStatusPathDialog.tsx | 2 +- .../playgrounds/PopoverPlaygroundPage.tsx | 15 +- .../pages/DefaultSettingsPage.tsx | 2 +- ts/components/inputs/SessionInput.tsx | 4 +- .../leftpane/LeftPaneMessageSection.tsx | 2 + .../menu/ConversationListItemContextMenu.tsx | 2 + ts/components/menu/Menu.tsx | 2 + .../menu/MessageRequestBannerContextMenu.tsx | 2 + .../CopyAccountId/CopyAccountIdMenuItem.tsx | 2 + .../CopyCommunityUrlMenuItem.tsx | 2 + .../menuAndSettingsHooks/useShowNoteToSelf.ts | 7 +- ts/contexts/MessagesContainerRefContext.tsx | 2 +- ...eDebouncedSelectAllOnTripleClickHandler.ts | 2 +- ts/hooks/useDebuncedSpellcheck.ts | 2 +- ts/test/components/renderComponent.tsx | 2 +- ts/types/Util.ts | 1 + yarn.lock | 1167 ++++++++++++++++- 32 files changed, 1361 insertions(+), 119 deletions(-) create mode 100644 babel.config.js diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..9b40c6619 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,175 @@ +const fs = require('fs'); +const { SourceMapConsumer } = require('source-map'); + +// ANSI color codes +const colors = { + reset: '\x1b[0m', + bright: '\x1b[1m', + dim: '\x1b[2m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m', + white: '\x1b[37m', + bgRed: '\x1b[41m', + bgYellow: '\x1b[43m', +}; + +// Cache for source map consumers +const sourceMapCache = new Map(); + +// Number of lines to show before/after error +const CONTEXT_LINES = 3; + +async function getOriginalLocation(jsFile, line, column) { + try { + const mapFile = `${jsFile}.map`; + + if (!fs.existsSync(mapFile)) { + return null; + } + + let consumer = sourceMapCache.get(mapFile); + if (!consumer) { + const rawSourceMap = JSON.parse(fs.readFileSync(mapFile, 'utf-8')); + consumer = await new SourceMapConsumer(rawSourceMap); + sourceMapCache.set(mapFile, consumer); + } + + const original = consumer.originalPositionFor({ line, column }); + return original.source ? original : null; + } catch (err) { + return null; + } +} + +function getSourceContent(jsFile) { + try { + const mapFile = `${jsFile}.map`; + if (!fs.existsSync(mapFile)) { + return null; + } + const rawSourceMap = JSON.parse(fs.readFileSync(mapFile, 'utf-8')); + if (rawSourceMap.sourcesContent && rawSourceMap.sourcesContent[0]) { + return { + content: rawSourceMap.sourcesContent[0], + sourceName: rawSourceMap.sources[0], + }; + } + return null; + } catch (err) { + return null; + } +} + +module.exports = { + presets: [ + ['@babel/preset-env', { modules: 'commonjs' }], + ], + plugins: [ + [require.resolve('babel-plugin-react-compiler'), { + target: '19', + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + const debug = process.env.SESSION_RC_DEBUG; + if (!debug) { + return; + } + + const errorLoc = event.detail?.options?.loc; + const fnLoc = event.fnLoc; + const reason = event.detail?.options?.reason || 'Unknown error'; + const category = event.detail?.options?.category || 'Unknown'; + + (async () => { + console.log(`\n${colors.red}${colors.bright}[CompileError]${colors.reset} ${colors.cyan}${filename}${colors.reset}`); + console.log(` ${colors.yellow}Category:${colors.reset} ${category}`); + console.log(` ${colors.yellow}Reason:${colors.reset} ${reason}`); + + if (!fnLoc || !errorLoc) { + return; + } + + // Try to get original TS source from source map + const sourceData = getSourceContent(filename); + let source; let sourceName; + + if (sourceData) { + source = sourceData.content; + sourceName = sourceData.sourceName; + } else { + source = fs.readFileSync(filename, 'utf-8'); + sourceName = filename; + } + + const lines = source.split('\n'); + + // Map JS locations to TS locations + let errStartLine = errorLoc.start.line; + let errEndLine = errorLoc.end.line; + let errColStart = errorLoc.start.column; + let errColEnd = errorLoc.end.column; + + if (sourceData) { + const errStartOrig = await getOriginalLocation(filename, errorLoc.start.line, errorLoc.start.column); + const errEndOrig = await getOriginalLocation(filename, errorLoc.end.line, errorLoc.end.column); + + if (errStartOrig) { + errStartLine = errStartOrig.line; + errColStart = errStartOrig.column; + } + if (errEndOrig) { + errEndLine = errEndOrig.line; + errColEnd = errEndOrig.column; + } + } + + // Show context around the error + const contextStart = Math.max(0, errStartLine - CONTEXT_LINES - 1); + const contextEnd = Math.min(lines.length, errEndLine + CONTEXT_LINES); + + console.log(` ${colors.yellow}Source:${colors.reset} ${colors.dim}${sourceName}${colors.reset}`); + console.log(` ${colors.yellow}Error at:${colors.reset} line ${errStartLine}, columns ${errColStart}-${errColEnd}`); + console.log(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + + for (let i = contextStart; i < contextEnd; i++) { + const lineNum = i + 1; + const lineNumStr = lineNum.toString().padStart(4, ' '); + const line = lines[i] || ''; + + const isErrorLine = lineNum >= errStartLine && lineNum <= errEndLine; + + if (isErrorLine) { + const gutter = `${colors.bgRed}${colors.white} ${lineNumStr} ${colors.reset}`; + + if (errColStart !== null && errColEnd !== null && lineNum === errStartLine) { + const before = line.substring(0, errColStart); + const highlight = line.substring(errColStart, errColEnd); + const after = line.substring(errColEnd); + console.log(` ${gutter} ${before}${colors.bgYellow}${colors.bright}${highlight}${colors.reset}${after}`); + + const underline = ' '.repeat(errColStart) + '^'.repeat(Math.max(1, errColEnd - errColStart)); + console.log(` ${colors.dim} ${colors.reset} ${colors.red}${underline}${colors.reset}`); + } else { + console.log(` ${gutter} ${colors.red}${line}${colors.reset}`); + } + } else { + const gutter = `${colors.dim} ${lineNumStr} ${colors.reset}`; + console.log(` ${gutter} ${line}`); + } + } + + console.log(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + })(); + } + }, + }, + }], + ], + only: [ + '**/ts/components/**', + ], +}; diff --git a/package.json b/package.json index abc805f93..3e44bfdff 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,11 @@ "main": "ts/mains/main_node.js", "resolutions": { "lodash": "^4.17.21", - "react": "18.3.1", - "@types/react": "18.3.3", + "react": "^19.0.0", + "@types/react": "^19.0.0", "@babel/runtime": "^7.26.10", - "nanoid": "^3.3.8" + "nanoid": "^3.3.8", + "csstype": "^3.1.3" }, "scripts": { "start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .", @@ -27,13 +28,20 @@ "start-dev:pretty": "yarn start-dev | pino-pretty", "start-perf": "cross-env NODE_ENV=development NODE_APP_INSTANCE=devprod$MULTI electron --inspect-brk=9229 --enable-precise-memory-info --js-flags=\"--expose-gc --allow-natives-syntax\" .", "start-dev:perf": "yarn start-perf | pino-pretty", - "build": "yarn print-deps && yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:locales-soft && tsc && yarn build:workers", + "build-pre": "yarn print-deps && yarn clean && yarn protobuf && yarn update-git-info && yarn sass && yarn build:locales-soft", + "build-tsc": "tsc", + "build-tsc:source-maps": "tsc --sourceMap --inlineSources", + "build-babel-react-compiler": "babel ts --out-dir ts --extensions .js", + "build-post": "yarn build:workers", + "build:no-compiler": "yarn build-pre && yarn build-tsc && yarn build-post", + "build": "yarn build-pre && yarn build-tsc && yarn build-babel-react-compiler && yarn build-post", + "build:compiler-debug": "yarn build-pre && yarn build-tsc:source-maps && cross-env SESSION_RC_DEBUG=1 yarn build-babel-react-compiler && yarn build-post", "build:workers": "yarn worker:utils && yarn worker:libsession && yarn worker:image_processor", "build:locales": "python3 ./tools/localization/generateLocales.py --generate-types --print-problems --error-on-problems --error-old-dynamic-variables", "build:locales-soft": "python3 ./tools/localization/generateLocales.py --generate-types --print-problems --print-problem-strings", "protobuf": "pbjs --target static-module --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js --force-long", "sass": "rimraf --glob 'stylesheets/dist/' && webpack --config=./sass.config.js", - "clean": "rimraf --glob 'ts/**/*.js' 'ts/*.js' 'ts/*.js.map' 'ts/**/*.js.map tsconfig.tsbuildinfo'", + "clean": "rimraf --glob 'ts/**/*.js' 'ts/*.js' 'ts/*.js.map' 'ts/**/*.js.map' 'tsconfig.tsbuildinfo'", "lint": "yarn format --cache && eslint --cache .", "format": "prettier --list-different --write \"*.{css,js,json,scss,ts,tsx}\" \"./**/*.{css,js,json,scss,ts,tsx}\"", "start-prod-test": "cross-env NODE_ENV=production NODE_APP_INSTANCE=$MULTI electron .", @@ -93,14 +101,14 @@ "protobufjs": "^7.4.0", "punycode": "^2.3.1", "qrcode.react": "^4.2.0", - "react": "18.3.1", + "react": "^19.0.0", "react-contexify": "^6.0.0", - "react-dom": "18.3.1", + "react-dom": "^19.0.0", "react-draggable": "^4.4.6", "react-error-boundary": "^5.0.0", "react-h5-audio-player": "^3.9.3", "react-intersection-observer": "^9.16.0", - "react-redux": "8.1.3", + "react-redux": "^9.0.0", "react-test-renderer": "^18.3.1", "react-toastify": "^10.0.0", "react-use": "^17.6.0", @@ -113,12 +121,15 @@ "sanitize.css": "^12.0.1", "semver": "^7.7.1", "sharp": "^0.34.4", - "styled-components": "^6.1.15", + "styled-components": "^6.1.19", "uuid": "11.1.0", "webrtc-adapter": "^4.2.2", "zod": "^3.24.2" }, "devDependencies": { + "@babel/cli": "^7.28.3", + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", "@commitlint/cli": "^19.8.0", "@commitlint/config-conventional": "^19.8.0", "@testing-library/jest-dom": "^6.4.6", @@ -140,22 +151,23 @@ "@types/lodash": "^4.17.16", "@types/mocha": "5.2.7", "@types/node-fetch": "^2.5.7", - "@types/react": "18.3.18", - "@types/react-dom": "18.3.5", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", "@types/react-redux": "^7.1.33", "@types/react-virtualized": "^9.21.30", "@types/rimraf": "4.0.5", "@types/semver": "7.5.8", "@types/sinon": "9.0.11", - "@types/styled-components": "^5.1.34", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "8.26.1", + "babel-plugin-react-compiler": "^1.0.0", "chai": "^4.5.0", "chai-as-promised": "^7.1.2", "chai-bytes": "^0.1.2", "concurrently": "^9.2.0", "cross-env": "^7.0.3", "css-loader": "^7.1.2", + "csstype": "^3.2.3", "electron": "34.2.0", "electron-builder": "26.0.0-alpha.8", "eslint": "8.57.1", @@ -181,6 +193,7 @@ "sass": "^1.85.1", "sass-loader": "^16.0.5", "sinon": "19.0.2", + "source-map": "^0.7.6", "ts-loader": "^9.5.2", "typescript": "^5.8.2", "webpack": "^5.98.0", diff --git a/ts/components/SessionTooltip.tsx b/ts/components/SessionTooltip.tsx index d9b21c49d..a9e206d24 100644 --- a/ts/components/SessionTooltip.tsx +++ b/ts/components/SessionTooltip.tsx @@ -51,9 +51,10 @@ export const SessionTooltip = ({ const [hovered, setHovered] = useState(false); const [debouncedHover, setDebouncedHover] = useState(false); - const ref = useRef(null); + const ref = useRef(null); - const triggerPos = useTriggerPosition(ref); + // FIXME: remove this as cast + const triggerPos = useTriggerPosition(ref as RefObject); useDebounce( () => { diff --git a/ts/components/SplitViewContainer.tsx b/ts/components/SplitViewContainer.tsx index b81806ad4..0a37b0784 100644 --- a/ts/components/SplitViewContainer.tsx +++ b/ts/components/SplitViewContainer.tsx @@ -2,8 +2,8 @@ import { ReactElement, ReactNode, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; type SplitViewProps = { - top: ReactElement; - bottom: ReactElement; + top: ReactElement; + bottom: ReactElement; disableTop: boolean; }; diff --git a/ts/components/basic/MessageBodyHighlight.tsx b/ts/components/basic/MessageBodyHighlight.tsx index b91461c2b..93d4e70fe 100644 --- a/ts/components/basic/MessageBodyHighlight.tsx +++ b/ts/components/basic/MessageBodyHighlight.tsx @@ -8,6 +8,8 @@ import { renderTextDefault, } from '../conversation/message/message-content/MessageBody'; +import type { JSX } from "react"; + const renderNewLines: RenderTextCallbackType = ({ text, key, isGroup, isPublic }) => ( ; + reference?: RefObject; className?: string; style?: CSSProperties; }; diff --git a/ts/components/conversation/AddMentions.tsx b/ts/components/conversation/AddMentions.tsx index de8e9e8df..1a4d67825 100644 --- a/ts/components/conversation/AddMentions.tsx +++ b/ts/components/conversation/AddMentions.tsx @@ -1,5 +1,5 @@ import styled from 'styled-components'; -import type { ReactNode } from 'react'; +import type { ReactNode, JSX } from 'react'; import { ConvoHub } from '../../session/conversations'; import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys'; import { PubKey } from '../../session/types'; diff --git a/ts/components/conversation/Emojify.tsx b/ts/components/conversation/Emojify.tsx index f8be50e46..16295eb28 100644 --- a/ts/components/conversation/Emojify.tsx +++ b/ts/components/conversation/Emojify.tsx @@ -2,6 +2,8 @@ import { SizeClassType } from '../../util/emoji'; import { RenderTextCallbackType } from '../../types/Util'; +import type { JSX } from "react"; + type Props = { text: string; /** A class name to be added to the generated emoji images */ diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx index 5913f395e..a712880b4 100644 --- a/ts/components/conversation/SessionConversation.tsx +++ b/ts/components/conversation/SessionConversation.tsx @@ -117,7 +117,7 @@ const GroupMarkedAsExpired = () => { }; export class SessionConversation extends Component { - private readonly messageContainerRef: RefObject; + private readonly messageContainerRef: RefObject; private dragCounter: number; private publicMembersRefreshTimeout?: NodeJS.Timeout; private readonly updateMemberList: () => any; diff --git a/ts/components/conversation/SessionMessagesListContainer.tsx b/ts/components/conversation/SessionMessagesListContainer.tsx index e104092b3..fa1fffe7c 100644 --- a/ts/components/conversation/SessionMessagesListContainer.tsx +++ b/ts/components/conversation/SessionMessagesListContainer.tsx @@ -32,7 +32,7 @@ import { StyledMentionAnother } from './AddMentions'; import { MessagesContainerRefContext } from '../../contexts/MessagesContainerRefContext'; export type SessionMessageListProps = { - messageContainerRef: RefObject; + messageContainerRef: RefObject; }; export const messageContainerDomID = 'messages-container'; diff --git a/ts/components/conversation/composition/CompositionBox.tsx b/ts/components/conversation/composition/CompositionBox.tsx index 6d335bfa7..bccd0b51e 100644 --- a/ts/components/conversation/composition/CompositionBox.tsx +++ b/ts/components/conversation/composition/CompositionBox.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { AbortController } from 'abort-controller'; import autoBind from 'auto-bind'; -import { Component, createRef, RefObject, KeyboardEvent } from 'react'; +import { Component, createRef, RefObject, KeyboardEvent, type JSX } from 'react'; import { FrequentlyUsed } from 'emoji-mart'; import * as MIME from '../../../types/MIME'; import { SessionEmojiPanel, StyledEmojiPanel } from '../SessionEmojiPanel'; @@ -217,10 +217,10 @@ const StyledCompositionBoxContainer = styled(Flex)` `; class CompositionBoxInner extends Component { - private readonly inputRef: RefObject; - private readonly fileInput: RefObject; - private container: RefObject; - private readonly emojiPanel: RefObject; + private readonly inputRef: RefObject; + private readonly fileInput: RefObject; + private container: RefObject; + private readonly emojiPanel: RefObject; private readonly emojiPanelButton: any; private linkPreviewAbortController?: AbortController; diff --git a/ts/components/conversation/composition/CompositionTextArea.tsx b/ts/components/conversation/composition/CompositionTextArea.tsx index 496406a93..edfbc2bab 100644 --- a/ts/components/conversation/composition/CompositionTextArea.tsx +++ b/ts/components/conversation/composition/CompositionTextArea.tsx @@ -49,8 +49,8 @@ type Props = { initialDraft: string; draft: string; setDraft: (draft: string) => void; - container: RefObject; - inputRef: RefObject; + container: RefObject; + inputRef: RefObject; typingEnabled: boolean; onKeyDown: KeyboardEventHandler; }; @@ -218,7 +218,7 @@ function useHandleSelect({ }: { focusedItem: SearchableSuggestion; handleMentionCleanup: () => void; - inputRef: RefObject; + inputRef: RefObject; mention: MentionDetails | null; results: Array; setDraft: Dispatch; @@ -326,7 +326,7 @@ function useHandleKeyDown({ handleMentionCheck: (content: string, htmlIndex?: number | null) => void; handleMentionCleanup: () => void; handleSelect: (item?: SessionSuggestionDataItem) => void; - inputRef: RefObject; + inputRef: RefObject; mention: MentionDetails | null; onKeyDown: KeyboardEventHandler; results: Array; diff --git a/ts/components/conversation/media-gallery/AttachmentSection.tsx b/ts/components/conversation/media-gallery/AttachmentSection.tsx index 9f869b6fa..22c6d2ba7 100644 --- a/ts/components/conversation/media-gallery/AttachmentSection.tsx +++ b/ts/components/conversation/media-gallery/AttachmentSection.tsx @@ -4,6 +4,8 @@ import { MediaItemType } from '../../lightbox/LightboxGallery'; import { DocumentListItem } from './DocumentListItem'; import { MediaGridItem } from './MediaGridItem'; +import type { JSX } from "react"; + type Props = { type: 'media' | 'documents'; mediaItems: Array; diff --git a/ts/components/conversation/message/message-content/MessageBody.tsx b/ts/components/conversation/message/message-content/MessageBody.tsx index f15cb36a9..0d9d7923c 100644 --- a/ts/components/conversation/message/message-content/MessageBody.tsx +++ b/ts/components/conversation/message/message-content/MessageBody.tsx @@ -3,7 +3,7 @@ import LinkifyIt from 'linkify-it'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; -import type { ReactNode } from 'react'; +import type { ReactNode, JSX } from 'react'; import { RenderTextCallbackType } from '../../../../types/Util'; import { getEmojiSizeClass, SizeClassType } from '../../../../util/emoji'; import { LinkPreviews } from '../../../../util/linkPreviews'; diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index 315621110..8b43c5a0d 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ -import { Dispatch, useCallback, useEffect, useRef, useState } from 'react'; +import { Dispatch, RefObject, useCallback, useEffect, useRef, useState } from 'react'; import { isNumber } from 'lodash'; import { ItemParams, Menu, useContextMenu } from 'react-contexify'; @@ -183,8 +183,9 @@ export const MessageContextMenu = (props: Props) => { const emojiPanelWidth = 354; const emojiPanelHeight = 435; - const contextMenuRef = useRef(null); - const { docX, docY } = useMouse(contextMenuRef); + const contextMenuRef = useRef(null); + // FIXME: remove as cast + const { docX, docY } = useMouse(contextMenuRef as RefObject); const [mouseX, setMouseX] = useState(0); const [mouseY, setMouseY] = useState(0); diff --git a/ts/components/dialog/OnionStatusPathDialog.tsx b/ts/components/dialog/OnionStatusPathDialog.tsx index 12bfe6a6b..6f05354f2 100644 --- a/ts/components/dialog/OnionStatusPathDialog.tsx +++ b/ts/components/dialog/OnionStatusPathDialog.tsx @@ -1,5 +1,5 @@ import { ipcRenderer } from 'electron'; -import { useState, SessionDataTestId } from 'react'; +import { useState, SessionDataTestId, type JSX } from 'react'; import { useDispatch } from 'react-redux'; import useHover from 'react-use/lib/useHover'; diff --git a/ts/components/dialog/debug/playgrounds/PopoverPlaygroundPage.tsx b/ts/components/dialog/debug/playgrounds/PopoverPlaygroundPage.tsx index 8b7b58c85..1c4da2ed7 100644 --- a/ts/components/dialog/debug/playgrounds/PopoverPlaygroundPage.tsx +++ b/ts/components/dialog/debug/playgrounds/PopoverPlaygroundPage.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from 'react'; +import { RefObject, useRef, useState } from 'react'; import styled from 'styled-components'; import useUpdate from 'react-use/lib/useUpdate'; import { SessionTooltip, type TooltipProps, useTriggerPosition } from '../../../SessionTooltip'; @@ -35,12 +35,13 @@ function PopoverGrid( const r5 = useRef(null); const r6 = useRef(null); - const t1 = useTriggerPosition(r1); - const t2 = useTriggerPosition(r2); - const t3 = useTriggerPosition(r3); - const t4 = useTriggerPosition(r4); - const t5 = useTriggerPosition(r5); - const t6 = useTriggerPosition(r6); + // FIXME: remove as cast + const t1 = useTriggerPosition(r1 as RefObject); + const t2 = useTriggerPosition(r2 as RefObject); + const t3 = useTriggerPosition(r3 as RefObject); + const t4 = useTriggerPosition(r4 as RefObject); + const t5 = useTriggerPosition(r5 as RefObject); + const t6 = useTriggerPosition(r6 as RefObject); return ( <> diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index ecbee53c5..3561c525d 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -61,7 +61,7 @@ const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialog const handleKeyCancel = ( mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void, - inputRef: RefObject + inputRef: RefObject ) => { switch (mode) { case 'qr': diff --git a/ts/components/inputs/SessionInput.tsx b/ts/components/inputs/SessionInput.tsx index 2d73de8b2..566aea2aa 100644 --- a/ts/components/inputs/SessionInput.tsx +++ b/ts/components/inputs/SessionInput.tsx @@ -247,8 +247,8 @@ type InputProps = Pick< onChange: (e: ChangeEvent) => void; }; -type WithInputRef = { inputRef?: RefObject }; -type WithTextAreaRef = { inputRef?: RefObject }; +type WithInputRef = { inputRef?: RefObject }; +type WithTextAreaRef = { inputRef?: RefObject }; function useUpdateInputValue(onValueChanged: (val: string) => void, disabled?: boolean) { return useCallback( diff --git a/ts/components/leftpane/LeftPaneMessageSection.tsx b/ts/components/leftpane/LeftPaneMessageSection.tsx index d18dbf888..e82fd0ad3 100644 --- a/ts/components/leftpane/LeftPaneMessageSection.tsx +++ b/ts/components/leftpane/LeftPaneMessageSection.tsx @@ -22,6 +22,8 @@ import { OverlayMessageRequest } from './overlay/OverlayMessageRequest'; import { OverlayChooseAction } from './overlay/choose-action/OverlayChooseAction'; import { sectionActions } from '../../state/ducks/section'; +import type { JSX } from "react"; + const StyledLeftPaneContent = styled.div` display: flex; flex-direction: column; diff --git a/ts/components/menu/ConversationListItemContextMenu.tsx b/ts/components/menu/ConversationListItemContextMenu.tsx index 2993f8a56..746a3dc4f 100644 --- a/ts/components/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/menu/ConversationListItemContextMenu.tsx @@ -36,6 +36,8 @@ import { import { tr } from '../../localization/localeTools'; import { useTogglePinConversationHandler } from '../menuAndSettingsHooks/UseTogglePinConversationHandler'; +import type { JSX } from "react"; + export type PropsContextConversationItem = { triggerId: string; }; diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 4e03441c1..dba99d5b6 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -38,6 +38,8 @@ import { useChangeNickname } from '../menuAndSettingsHooks/useChangeNickname'; import { useShowNoteToSelfCb } from '../menuAndSettingsHooks/useShowNoteToSelf'; import { useShowUserDetailsCbFromConversation } from '../menuAndSettingsHooks/useShowUserDetailsCb'; +import type { JSX } from "react"; + /** Menu items standardized */ export const InviteContactMenuItem = (): JSX.Element | null => { diff --git a/ts/components/menu/MessageRequestBannerContextMenu.tsx b/ts/components/menu/MessageRequestBannerContextMenu.tsx index 978402424..a3b165c55 100644 --- a/ts/components/menu/MessageRequestBannerContextMenu.tsx +++ b/ts/components/menu/MessageRequestBannerContextMenu.tsx @@ -8,6 +8,8 @@ import { ItemWithDataTestId } from './items/MenuItemWithDataTestId'; import { getMenuAnimation } from './MenuAnimation'; import { tr } from '../../localization/localeTools'; +import type { JSX } from "react"; + export type PropsContextConversationItem = { triggerId: string; }; diff --git a/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx b/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx index c6938bbce..2c2b42dad 100644 --- a/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx +++ b/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx @@ -2,6 +2,8 @@ import { Localizer } from '../../../basic/Localizer'; import { useShowCopyAccountIdCb } from '../../../menuAndSettingsHooks/useCopyAccountId'; import { ItemWithDataTestId } from '../MenuItemWithDataTestId'; +import type { JSX } from "react"; + /** * Can be used to copy the conversation AccountID or the message's author sender'id. * Depending on what the pubkey is diff --git a/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx b/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx index ee54207d4..a1851cb4a 100644 --- a/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx +++ b/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx @@ -2,6 +2,8 @@ import { Localizer } from '../../../basic/Localizer'; import { useShowCopyCommunityUrlCb } from '../../../menuAndSettingsHooks/useCopyCommunityUrl'; import { ItemWithDataTestId } from '../MenuItemWithDataTestId'; +import type { JSX } from "react"; + export const CopyCommunityUrlMenuItem = ({ convoId }: { convoId: string }): JSX.Element | null => { const copyCommunityUrlCb = useShowCopyCommunityUrlCb(convoId); diff --git a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts index 0b1c2050f..87a305cb7 100644 --- a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts +++ b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts @@ -12,9 +12,14 @@ function useShowNoteToSelf({ conversationId }: { conversationId: string }) { return isMe && isHidden; } +function useDispatch2() { + const dispatch = useDispatch(); + return { dispatch } +} + export function useShowNoteToSelfCb({ conversationId }: { conversationId: string }) { const showNTS = useShowNoteToSelf({ conversationId }); - const dispatch = useDispatch(); + const { dispatch } = useDispatch2(); if (!showNTS) { return null; diff --git a/ts/contexts/MessagesContainerRefContext.tsx b/ts/contexts/MessagesContainerRefContext.tsx index 84cf81a6f..a6b1d6cbe 100644 --- a/ts/contexts/MessagesContainerRefContext.tsx +++ b/ts/contexts/MessagesContainerRefContext.tsx @@ -1,6 +1,6 @@ import { createContext, RefObject, useContext } from 'react'; -export const MessagesContainerRefContext = createContext>({ +export const MessagesContainerRefContext = createContext>({ current: null, }); diff --git a/ts/hooks/useDebouncedSelectAllOnTripleClickHandler.ts b/ts/hooks/useDebouncedSelectAllOnTripleClickHandler.ts index 34d0521bd..413c391d9 100644 --- a/ts/hooks/useDebouncedSelectAllOnTripleClickHandler.ts +++ b/ts/hooks/useDebouncedSelectAllOnTripleClickHandler.ts @@ -19,7 +19,7 @@ function selectAllContent(el: HTMLElement) { } interface DebouncedSelectAllOnTripleClickHandlerProps { - elementRef: RefObject; + elementRef: RefObject; onClick?: MouseEventHandler; } diff --git a/ts/hooks/useDebuncedSpellcheck.ts b/ts/hooks/useDebuncedSpellcheck.ts index 94c44882b..0098a014a 100644 --- a/ts/hooks/useDebuncedSpellcheck.ts +++ b/ts/hooks/useDebuncedSpellcheck.ts @@ -2,7 +2,7 @@ import { type RefObject, useCallback, useEffect } from 'react'; import { debounce } from 'lodash'; interface DebouncedSpellcheckProps { - elementRef: RefObject; + elementRef: RefObject; delay?: number; } diff --git a/ts/test/components/renderComponent.tsx b/ts/test/components/renderComponent.tsx index d462deb8a..c0360ce0f 100644 --- a/ts/test/components/renderComponent.tsx +++ b/ts/test/components/renderComponent.tsx @@ -28,7 +28,7 @@ const Providers = ({ children }: { children: ReactNode }) => { ); }; -function renderComponent(children: ReactElement): TestRenderer.ReactTestRenderer { +function renderComponent(children: ReactElement): TestRenderer.ReactTestRenderer { return TestRenderer.create({children}); } diff --git a/ts/types/Util.ts b/ts/types/Util.ts index 85348ec86..e543f8812 100644 --- a/ts/types/Util.ts +++ b/ts/types/Util.ts @@ -1,3 +1,4 @@ +import type { JSX } from "react"; export type RenderTextCallbackType = (options: { text: string; key: number; diff --git a/yarn.lock b/yarn.lock index e0ffdc257..d75f43012 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,22 @@ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== +"@babel/cli@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.28.3.tgz#f33693753bc103ab0084a5776ccf8ab8a140038b" + integrity sha512-n1RU5vuCX0CsaqaXm9I0KUCNKNQMy5epmzl/xdSSm70bSqhg9GWhgeosypyQLc0bK24+Xpk1WGzZlI9pJtkZdg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.28" + commander "^6.2.0" + convert-source-map "^2.0.0" + fs-readdir-recursive "^1.1.0" + glob "^7.2.0" + make-dir "^2.1.0" + slash "^2.0.0" + optionalDependencies: + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" + chokidar "^3.6.0" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" @@ -20,11 +36,208 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2", "@babel/compat-data@^7.27.7", "@babel/compat-data@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f" + integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== + +"@babel/core@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" + integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298" + integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== + dependencies: + "@babel/parser" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": + version "7.27.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" + integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== + dependencies: + "@babel/types" "^7.27.3" + +"@babel/helper-compilation-targets@^7.27.1", "@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.27.1", "@babel/helper-create-class-features-plugin@^7.28.3": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz#472d0c28028850968979ad89f173594a6995da46" + integrity sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-member-expression-to-functions" "^7.28.5" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.28.5" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.27.1": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz#7c1ddd64b2065c7f78034b25b43346a7e19ed997" + integrity sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + regexpu-core "^6.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz#742ccf1cb003c07b48859fc9fa2c1bbe40e5f753" + integrity sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg== + dependencies: + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + debug "^4.4.1" + lodash.debounce "^4.0.8" + resolve "^1.22.10" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-member-expression-to-functions@^7.27.1", "@babel/helper-member-expression-to-functions@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz#f3e07a10be37ed7a63461c63e6929575945a6150" + integrity sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg== + dependencies: + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/helper-optimise-call-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" + integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-remap-async-to-generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz#4601d5c7ce2eb2aea58328d43725523fcd362ce6" + integrity sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-wrap-function" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-replace-supers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz#b1ed2d634ce3bdb730e4b52de30f8cccfd692bc0" + integrity sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.27.1" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-skip-transparent-expression-wrappers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" + integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helper-wrap-function@^7.27.1": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz#fe4872092bc1438ffd0ce579e6f699609f9d0a7a" + integrity sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g== + dependencies: + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.3" + "@babel/types" "^7.28.2" + +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + "@babel/highlight@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" @@ -40,13 +253,598 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.26.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/parser@^7.27.2", "@babel/parser@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08" + integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== + dependencies: + "@babel/types" "^7.28.5" + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz#fbde57974707bbfa0376d34d425ff4fa6c732421" + integrity sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.5" + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz#43f70a6d7efd52370eefbdf55ae03d91b293856d" + integrity sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz#beb623bd573b8b6f3047bd04c32506adc3e58a72" + integrity sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz#e134a5479eb2ba9c02714e8c1ebf1ec9076124fd" + integrity sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-optional-chaining" "^7.27.1" + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz#373f6e2de0016f73caf8f27004f61d167743742a" + integrity sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-syntax-import-assertions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz#88894aefd2b03b5ee6ad1562a7c8e1587496aecd" + integrity sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-attributes@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz#6e2061067ba3ab0266d834a9f94811196f2aba9a" + integrity sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-async-generator-functions@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz#1276e6c7285ab2cd1eccb0bc7356b7a69ff842c2" + integrity sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/traverse" "^7.28.0" + +"@babel/plugin-transform-async-to-generator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz#9a93893b9379b39466c74474f55af03de78c66e7" + integrity sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-remap-async-to-generator" "^7.27.1" + +"@babel/plugin-transform-block-scoped-functions@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz#558a9d6e24cf72802dd3b62a4b51e0d62c0f57f9" + integrity sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-block-scoping@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz#e0d3af63bd8c80de2e567e690a54e84d85eb16f6" + integrity sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-class-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz#dd40a6a370dfd49d32362ae206ddaf2bb082a925" + integrity sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-class-static-block@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz#d1b8e69b54c9993bc558203e1f49bfc979bfd852" + integrity sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.3" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-classes@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz#75d66175486788c56728a73424d67cbc7473495c" + integrity sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-globals" "^7.28.0" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + "@babel/traverse" "^7.28.4" + +"@babel/plugin-transform-computed-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz#81662e78bf5e734a97982c2b7f0a793288ef3caa" + integrity sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/template" "^7.27.1" + +"@babel/plugin-transform-destructuring@^7.28.0", "@babel/plugin-transform-destructuring@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz#b8402764df96179a2070bb7b501a1586cf8ad7a7" + integrity sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.28.5" + +"@babel/plugin-transform-dotall-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz#aa6821de864c528b1fecf286f0a174e38e826f4d" + integrity sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-duplicate-keys@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz#f1fbf628ece18e12e7b32b175940e68358f546d1" + integrity sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz#5043854ca620a94149372e69030ff8cb6a9eb0ec" + integrity sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-dynamic-import@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz#4c78f35552ac0e06aa1f6e3c573d67695e8af5a4" + integrity sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-explicit-resource-management@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz#45be6211b778dbf4b9d54c4e8a2b42fa72e09a1a" + integrity sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.0" + +"@babel/plugin-transform-exponentiation-operator@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz#7cc90a8170e83532676cfa505278e147056e94fe" + integrity sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-export-namespace-from@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz#71ca69d3471edd6daa711cf4dfc3400415df9c23" + integrity sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-for-of@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz#bc24f7080e9ff721b63a70ac7b2564ca15b6c40a" + integrity sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-function-name@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz#4d0bf307720e4dce6d7c30fcb1fd6ca77bdeb3a7" + integrity sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ== + dependencies: + "@babel/helper-compilation-targets" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/plugin-transform-json-strings@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz#a2e0ce6ef256376bd527f290da023983527a4f4c" + integrity sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz#baaefa4d10a1d4206f9dcdda50d7d5827bb70b24" + integrity sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-logical-assignment-operators@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz#d028fd6db8c081dee4abebc812c2325e24a85b0e" + integrity sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-member-expression-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz#37b88ba594d852418e99536f5612f795f23aeaf9" + integrity sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-amd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz#a4145f9d87c2291fe2d05f994b65dba4e3e7196f" + integrity sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-commonjs@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz#8e44ed37c2787ecc23bdc367f49977476614e832" + integrity sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-modules-systemjs@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz#7439e592a92d7670dfcb95d0cbc04bd3e64801d2" + integrity sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew== + dependencies: + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.5" + +"@babel/plugin-transform-modules-umd@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz#63f2cf4f6dc15debc12f694e44714863d34cd334" + integrity sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w== + dependencies: + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz#f32b8f7818d8fc0cc46ee20a8ef75f071af976e1" + integrity sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-new-target@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz#259c43939728cad1706ac17351b7e6a7bea1abeb" + integrity sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz#4f9d3153bf6782d73dd42785a9d22d03197bc91d" + integrity sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-numeric-separator@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz#614e0b15cc800e5997dadd9bd6ea524ed6c819c6" + integrity sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-object-rest-spread@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz#9ee1ceca80b3e6c4bac9247b2149e36958f7f98d" + integrity sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew== + dependencies: + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.0" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/traverse" "^7.28.4" + +"@babel/plugin-transform-object-super@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz#1c932cd27bf3874c43a5cac4f43ebf970c9871b5" + integrity sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-replace-supers" "^7.27.1" + +"@babel/plugin-transform-optional-catch-binding@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz#84c7341ebde35ccd36b137e9e45866825072a30c" + integrity sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-optional-chaining@^7.27.1", "@babel/plugin-transform-optional-chaining@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz#8238c785f9d5c1c515a90bf196efb50d075a4b26" + integrity sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-parameters@^7.27.7": + version "7.27.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz#1fd2febb7c74e7d21cf3b05f7aebc907940af53a" + integrity sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-private-methods@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz#fdacbab1c5ed81ec70dfdbb8b213d65da148b6af" + integrity sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-private-property-in-object@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz#4dbbef283b5b2f01a21e81e299f76e35f900fb11" + integrity sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.1" + "@babel/helper-create-class-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-property-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz#07eafd618800591e88073a0af1b940d9a42c6424" + integrity sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-regenerator@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz#9d3fa3bebb48ddd0091ce5729139cd99c67cea51" + integrity sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-regexp-modifiers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz#df9ba5577c974e3f1449888b70b76169998a6d09" + integrity sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-reserved-words@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz#40fba4878ccbd1c56605a4479a3a891ac0274bb4" + integrity sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-shorthand-properties@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz#532abdacdec87bfee1e0ef8e2fcdee543fe32b90" + integrity sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-spread@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz#1a264d5fc12750918f50e3fe3e24e437178abb08" + integrity sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + +"@babel/plugin-transform-sticky-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz#18984935d9d2296843a491d78a014939f7dcd280" + integrity sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-template-literals@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz#1a0eb35d8bb3e6efc06c9fd40eb0bcef548328b8" + integrity sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-typeof-symbol@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz#70e966bb492e03509cf37eafa6dcc3051f844369" + integrity sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-escapes@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz#3e3143f8438aef842de28816ece58780190cf806" + integrity sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-property-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz#bdfe2d3170c78c5691a3c3be934c8c0087525956" + integrity sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz#25948f5c395db15f609028e370667ed8bae9af97" + integrity sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-unicode-sets-regex@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz#6ab706d10f801b5c72da8bb2548561fa04193cd1" + integrity sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.27.1" + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/preset-env@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.28.5.tgz#82dd159d1563f219a1ce94324b3071eb89e280b0" + integrity sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg== + dependencies: + "@babel/compat-data" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.28.5" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.27.1" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.27.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.27.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.28.3" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions" "^7.27.1" + "@babel/plugin-syntax-import-attributes" "^7.27.1" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.27.1" + "@babel/plugin-transform-async-generator-functions" "^7.28.0" + "@babel/plugin-transform-async-to-generator" "^7.27.1" + "@babel/plugin-transform-block-scoped-functions" "^7.27.1" + "@babel/plugin-transform-block-scoping" "^7.28.5" + "@babel/plugin-transform-class-properties" "^7.27.1" + "@babel/plugin-transform-class-static-block" "^7.28.3" + "@babel/plugin-transform-classes" "^7.28.4" + "@babel/plugin-transform-computed-properties" "^7.27.1" + "@babel/plugin-transform-destructuring" "^7.28.5" + "@babel/plugin-transform-dotall-regex" "^7.27.1" + "@babel/plugin-transform-duplicate-keys" "^7.27.1" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-dynamic-import" "^7.27.1" + "@babel/plugin-transform-explicit-resource-management" "^7.28.0" + "@babel/plugin-transform-exponentiation-operator" "^7.28.5" + "@babel/plugin-transform-export-namespace-from" "^7.27.1" + "@babel/plugin-transform-for-of" "^7.27.1" + "@babel/plugin-transform-function-name" "^7.27.1" + "@babel/plugin-transform-json-strings" "^7.27.1" + "@babel/plugin-transform-literals" "^7.27.1" + "@babel/plugin-transform-logical-assignment-operators" "^7.28.5" + "@babel/plugin-transform-member-expression-literals" "^7.27.1" + "@babel/plugin-transform-modules-amd" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.27.1" + "@babel/plugin-transform-modules-systemjs" "^7.28.5" + "@babel/plugin-transform-modules-umd" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-new-target" "^7.27.1" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.27.1" + "@babel/plugin-transform-numeric-separator" "^7.27.1" + "@babel/plugin-transform-object-rest-spread" "^7.28.4" + "@babel/plugin-transform-object-super" "^7.27.1" + "@babel/plugin-transform-optional-catch-binding" "^7.27.1" + "@babel/plugin-transform-optional-chaining" "^7.28.5" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/plugin-transform-private-methods" "^7.27.1" + "@babel/plugin-transform-private-property-in-object" "^7.27.1" + "@babel/plugin-transform-property-literals" "^7.27.1" + "@babel/plugin-transform-regenerator" "^7.28.4" + "@babel/plugin-transform-regexp-modifiers" "^7.27.1" + "@babel/plugin-transform-reserved-words" "^7.27.1" + "@babel/plugin-transform-shorthand-properties" "^7.27.1" + "@babel/plugin-transform-spread" "^7.27.1" + "@babel/plugin-transform-sticky-regex" "^7.27.1" + "@babel/plugin-transform-template-literals" "^7.27.1" + "@babel/plugin-transform-typeof-symbol" "^7.27.1" + "@babel/plugin-transform-unicode-escapes" "^7.27.1" + "@babel/plugin-transform-unicode-property-regex" "^7.27.1" + "@babel/plugin-transform-unicode-regex" "^7.27.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.27.1" + "@babel/preset-modules" "0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2 "^0.4.14" + babel-plugin-polyfill-corejs3 "^0.13.0" + babel-plugin-polyfill-regenerator "^0.6.5" + core-js-compat "^3.43.0" + semver "^6.3.1" + +"@babel/preset-modules@0.1.6-no-external-plugins": + version "0.1.6-no-external-plugins" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" + integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.26.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw== dependencies: regenerator-runtime "^0.14.0" +"@babel/template@^7.27.1", "@babel/template@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.0", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.4", "@babel/traverse@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" + integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.5" + debug "^4.3.1" + +"@babel/types@^7.26.0", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.4.4": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" + integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + "@commitlint/cli@^19.8.0": version "19.8.0" resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.8.0.tgz#e66e5a5268437e42b7c6f2a447e94ea83b8a3272" @@ -590,6 +1388,14 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@jridgewell/gen-mapping@^0.3.12": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" @@ -599,6 +1405,14 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" @@ -622,6 +1436,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -630,6 +1449,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jsdoc/salty@^0.2.1": version "0.2.8" resolved "https://registry.yarnpkg.com/@jsdoc/salty/-/salty-0.2.8.tgz#8d29923a9429694a437a50ab75004b576131d597" @@ -663,6 +1490,11 @@ "@emnapi/runtime" "^1.3.1" "@tybys/wasm-util" "^0.9.0" +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": + version "2.1.8-no-fsevents.3" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1094,7 +1926,7 @@ dependencies: "@types/node" "*" -"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1": +"@types/hoist-non-react-statics@^3.3.0": version "3.3.5" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg== @@ -1223,11 +2055,16 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== -"@types/react-dom@18.3.5", "@types/react-dom@^18.0.0": +"@types/react-dom@^18.0.0": version "18.3.5" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.5.tgz#45f9f87398c5dcea085b715c58ddcf1faf65f716" integrity sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q== +"@types/react-dom@^19.0.0": + version "19.2.3" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c" + integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== + "@types/react-redux@^7.1.33": version "7.1.33" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" @@ -1253,21 +2090,12 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react@*", "@types/react@18.3.18", "@types/react@^18": - version "18.3.18" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.18.tgz#9b382c4cd32e13e463f97df07c2ee3bbcd26904b" - integrity sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ== - dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" - -"@types/react@18.3.3": - version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" - integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== +"@types/react@*", "@types/react@^18", "@types/react@^19.0.0": + version "19.2.7" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.7.tgz#84e62c0f23e8e4e5ac2cadcea1ffeacccae7f62f" + integrity sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg== dependencies: - "@types/prop-types" "*" - csstype "^3.0.2" + csstype "^3.2.2" "@types/responselike@^1.0.0": version "1.0.3" @@ -1305,15 +2133,6 @@ resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz#5fd3592ff10c1e9695d377020c033116cc2889f2" integrity sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ== -"@types/styled-components@^5.1.34": - version "5.1.34" - resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.34.tgz#4107df8ef8a7eaba4fa6b05f78f93fba4daf0300" - integrity sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA== - dependencies: - "@types/hoist-non-react-statics" "*" - "@types/react" "*" - csstype "^3.0.2" - "@types/stylis@4.2.5": version "4.2.5" resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.5.tgz#1daa6456f40959d06157698a653a9ab0a70281df" @@ -1329,10 +2148,10 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== -"@types/use-sync-external-store@^0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" - integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== +"@types/use-sync-external-store@^0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc" + integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg== "@types/verror@^1.10.3": version "1.10.10" @@ -2065,6 +2884,37 @@ axios@^1.6.5: form-data "^4.0.4" proxy-from-env "^1.1.0" +babel-plugin-polyfill-corejs2@^0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz#8101b82b769c568835611542488d463395c2ef8f" + integrity sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg== + dependencies: + "@babel/compat-data" "^7.27.7" + "@babel/helper-define-polyfill-provider" "^0.6.5" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz#bb7f6aeef7addff17f7602a08a6d19a128c30164" + integrity sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.5" + core-js-compat "^3.43.0" + +babel-plugin-polyfill-regenerator@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz#32752e38ab6f6767b92650347bf26a31b16ae8c5" + integrity sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.5" + +babel-plugin-react-compiler@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz#bdf7360a23a4d5ebfca090255da3893efd07425f" + integrity sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw== + dependencies: + "@babel/types" "^7.26.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -2075,6 +2925,11 @@ base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +baseline-browser-mapping@^2.9.0: + version "2.9.4" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.4.tgz#a010e50ea6da48fba78179aef9b6e771d00fff42" + integrity sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -2160,6 +3015,17 @@ browserslist@^4.24.0: node-releases "^2.0.19" update-browserslist-db "^1.1.1" +browserslist@^4.28.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + buffer-crc32@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" @@ -2317,6 +3183,11 @@ caniuse-lite@^1.0.30001688: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001705.tgz#dc3510bcdef261444ca944b7be9c8d0bb7fafeef" integrity sha512-S0uyMMiYvA7CxNgomYBwwwPUnWzFD83f3B1ce5jHUfHTH//QL6hHsreI8RVC5606R4ssqravelYO5TU6t8sEyg== +caniuse-lite@^1.0.30001759: + version "1.0.30001759" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz#d569e7b010372c6b0ca3946e30dada0a2e9d5006" + integrity sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw== + catharsis@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121" @@ -2386,7 +3257,7 @@ check-error@^1.0.2, check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -chokidar@^3.5.3: +chokidar@^3.5.3, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -2567,6 +3438,11 @@ commander@^5.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + compare-func@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" @@ -2647,6 +3523,11 @@ conventional-commits-parser@^5.0.0: meow "^12.0.1" split2 "^4.0.0" +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + copy-to-clipboard@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" @@ -2654,6 +3535,13 @@ copy-to-clipboard@^3.3.1: dependencies: toggle-selection "^1.0.6" +core-js-compat@^3.43.0: + version "3.47.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.47.0.tgz#698224bbdbb6f2e3f39decdda4147b161e3772a3" + integrity sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ== + dependencies: + browserslist "^4.28.0" + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2759,10 +3647,10 @@ cssstyle@^3.0.0: dependencies: rrweb-cssom "^0.6.0" -csstype@3.1.3, csstype@^3.0.2, csstype@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +csstype@3.1.3, csstype@^3.0.2, csstype@^3.1.2, csstype@^3.1.3, csstype@^3.2.2, csstype@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== "curve25519-js@https://github.com/session-foundation/curve25519-js": version "0.0.4" @@ -2819,7 +3707,7 @@ dateformat@^4.6.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== -debug@4, debug@^4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0: +debug@4, debug@^4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@^4.4.0, debug@^4.4.1: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -3111,6 +3999,11 @@ electron-publish@26.0.0-alpha.8: lazy-val "^1.0.5" mime "^2.5.2" +electron-to-chromium@^1.5.263: + version "1.5.266" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz#41ed029b3cf641c4ee071de42954b36dca8f5f4e" + integrity sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg== + electron-to-chromium@^1.5.73: version "1.5.119" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.119.tgz#4e105e419209b33e1c44b4d1b5fc6fb27fac0209" @@ -3937,6 +4830,11 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: dependencies: minipass "^3.0.0" +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3983,6 +4881,11 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -4092,7 +4995,7 @@ glob@^11.0.0: package-json-from-dist "^1.0.0" path-scurry "^2.0.0" -glob@^7.1.3, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4256,7 +5159,7 @@ help-me@^5.0.0: resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -4547,7 +5450,7 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-core-module@^2.13.0, is-core-module@^2.15.1: +is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.1: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== @@ -4918,6 +5821,11 @@ jsdom@^22.1.0: ws "^8.13.0" xml-name-validator "^4.0.0" +jsesc@^3.0.2, jsesc@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -5138,6 +6046,11 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" @@ -5250,6 +6163,13 @@ lru-cache@^11.0.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.0.2.tgz#fbd8e7cf8211f5e7e5d91905c415a3f55755ca39" integrity sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -5267,6 +6187,14 @@ lz-string@^1.5.0: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + make-fetch-happen@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" @@ -5696,6 +6624,11 @@ node-releases@^2.0.19: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + nopt@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-6.0.0.tgz#245801d8ebf409c6df22ab9d95b65e1309cdb16d" @@ -6102,6 +7035,11 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pino-abstract-transport@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz#de241578406ac7b8a33ce0d77ae6e8a0b3b68a60" @@ -6398,13 +7336,12 @@ react-contexify@^6.0.0: dependencies: clsx "^1.2.1" -react-dom@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" - integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== +react-dom@^19.0.0: + version "19.2.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.1.tgz#ce3527560bda4f997e47d10dab754825b3061f59" + integrity sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg== dependencies: - loose-envify "^1.1.0" - scheduler "^0.23.2" + scheduler "^0.27.0" react-draggable@^4.4.6: version "4.4.6" @@ -6434,7 +7371,7 @@ react-intersection-observer@^9.16.0: resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz#7376d54edc47293300961010844d53b273ee0fb9" integrity sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA== -"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.3.1: +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== @@ -6454,17 +7391,13 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-redux@8.1.3: - version "8.1.3" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.3.tgz#4fdc0462d0acb59af29a13c27ffef6f49ab4df46" - integrity sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw== +react-redux@^9.0.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5" + integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== dependencies: - "@babel/runtime" "^7.12.1" - "@types/hoist-non-react-statics" "^3.3.1" - "@types/use-sync-external-store" "^0.0.3" - hoist-non-react-statics "^3.3.2" - react-is "^18.0.0" - use-sync-external-store "^1.0.0" + "@types/use-sync-external-store" "^0.0.6" + use-sync-external-store "^1.4.0" react-shallow-renderer@^16.15.0: version "16.15.0" @@ -6527,12 +7460,10 @@ react-virtualized@^9.22.6: prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" -react@18.3.1: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" - integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== - dependencies: - loose-envify "^1.1.0" +react@^19.0.0: + version "19.2.1" + resolved "https://registry.yarnpkg.com/react/-/react-19.2.1.tgz#8600fa205e58e2e807f6ef431c9f6492591a2700" + integrity sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw== read-binary-file-arch@^1.0.6: version "1.0.6" @@ -6625,6 +7556,18 @@ reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: get-proto "^1.0.1" which-builtin-type "^1.2.1" +regenerate-unicode-properties@^10.2.2: + version "10.2.2" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz#aa113812ba899b630658c7623466be71e1f86f66" + integrity sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" @@ -6642,6 +7585,30 @@ regexp.prototype.flags@^1.5.3: gopd "^1.2.0" set-function-name "^2.0.2" +regexpu-core@^6.3.1: + version "6.4.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.4.0.tgz#3580ce0c4faedef599eccb146612436b62a176e5" + integrity sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.2.2" + regjsgen "^0.8.0" + regjsparser "^0.13.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.2.1" + +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.13.0.tgz#01f8351335cf7898d43686bc74d2dd71c847ecc0" + integrity sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q== + dependencies: + jsesc "~3.1.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6717,6 +7684,15 @@ resolve@^1.20.0, resolve@^1.22.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.10: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" @@ -6925,6 +7901,11 @@ scheduler@^0.23.2: dependencies: loose-envify "^1.1.0" +scheduler@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd" + integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q== + schema-utils@^4.0.0, schema-utils@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.0.tgz#3b669f04f71ff2dfb5aba7ce2d5a9d79b35622c0" @@ -6955,6 +7936,11 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== +semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -7226,6 +8212,11 @@ source-map@^0.7.4: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +source-map@^0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + split2@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" @@ -7423,10 +8414,10 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -styled-components@^6.1.15: - version "6.1.15" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.15.tgz#7651904d5424d08c1046056eb39024cc23c72ab7" - integrity sha512-PpOTEztW87Ua2xbmLa7yssjNyUF9vE7wdldRfn1I2E6RTkqknkBYpj771OxM/xrvRGinLy2oysa7GOd7NcZZIA== +styled-components@^6.1.19: + version "6.1.19" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.19.tgz#9a41b4db79a3b7a2477daecabe8dd917235263d6" + integrity sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA== dependencies: "@emotion/is-prop-valid" "1.2.2" "@emotion/unitless" "0.8.1" @@ -7821,6 +8812,29 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz#65a7adfad8574c219890e219285ce4c64ed67eaa" + integrity sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz#301d4f8a43d2b75c97adfad87c9dd5350c9475d1" + integrity sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ== + unicorn-magic@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" @@ -7863,6 +8877,14 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.1" +update-browserslist-db@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz#cfb4358afa08b3d5731a2ecd95eebf4ddef8033e" + integrity sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -7888,10 +8910,10 @@ use-strict@1.0.1: resolved "https://registry.yarnpkg.com/use-strict/-/use-strict-1.0.1.tgz#0bb80d94f49a4a05192b84a8c7d34e95f1a7e3a0" integrity sha512-IeiWvvEXfW5ltKVMkxq6FvNf2LojMKvB2OCeja6+ct24S1XOmQw2dGr2JyndwACWAGJva9B7yPHwAmeA9QCqAQ== -use-sync-external-store@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" - integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== +use-sync-external-store@^1.4.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" + integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== utf8-byte-length@^1.0.1: version "1.0.5" @@ -8190,6 +9212,11 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" From b8367c993a620e5502be127de48a031c912059b7 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Tue, 9 Dec 2025 15:28:23 +1100 Subject: [PATCH 03/35] fix: redux react 19 support --- babel.config.js | 14 ++- package.json | 7 +- .../menuAndSettingsHooks/useHideNoteToSelf.ts | 4 +- .../menuAndSettingsHooks/useShowNoteToSelf.ts | 15 ++- ts/state/createStore.ts | 4 + ts/state/dispatch.ts | 9 ++ ts/state/reducer.ts | 3 + yarn.lock | 93 ++++++++----------- 8 files changed, 79 insertions(+), 70 deletions(-) create mode 100644 ts/state/dispatch.ts diff --git a/babel.config.js b/babel.config.js index 9b40c6619..162240aa9 100644 --- a/babel.config.js +++ b/babel.config.js @@ -66,13 +66,22 @@ function getSourceContent(jsFile) { module.exports = { presets: [ - ['@babel/preset-env', { modules: 'commonjs' }], + ['@babel/preset-env', { + modules: 'commonjs', + targets: { + electron: '34', // or whatever version you're using + }, + }], ], plugins: [ [require.resolve('babel-plugin-react-compiler'), { target: '19', logger: { logEvent(filename, event) { + if (filename.includes('useAppDispatch')) { + console.log('Processing useAppDispatch:', event.kind); + } + if (event.kind === 'CompileError') { const debug = process.env.SESSION_RC_DEBUG; if (!debug) { @@ -171,5 +180,8 @@ module.exports = { ], only: [ '**/ts/components/**', + '**/ts/components/*', + '**/ts/state/**', + '**/ts/state/*', ], }; diff --git a/package.json b/package.json index 3e44bfdff..7a64460b6 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "dependencies": { "@emoji-mart/data": "^1.2.1", "@emoji-mart/react": "^1.1.1", - "@reduxjs/toolkit": "^1.9.7", + "@reduxjs/toolkit": "^2.11.1", "@signalapp/better-sqlite3": "9.0.13", "@types/react-test-renderer": "^18.3.1", "abort-controller": "3.0.0", @@ -108,13 +108,13 @@ "react-error-boundary": "^5.0.0", "react-h5-audio-player": "^3.9.3", "react-intersection-observer": "^9.16.0", - "react-redux": "^9.0.0", + "react-redux": "^9.2.0", "react-test-renderer": "^18.3.1", "react-toastify": "^10.0.0", "react-use": "^17.6.0", "react-virtualized": "^9.22.6", "read-last-lines": "^1.8.0", - "redux": "4.2.1", + "redux": "^5.0.1", "redux-persist": "^6.0.0", "redux-promise-middleware": "^6.2.0", "rimraf": "6.0.1", @@ -153,7 +153,6 @@ "@types/node-fetch": "^2.5.7", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", - "@types/react-redux": "^7.1.33", "@types/react-virtualized": "^9.21.30", "@types/rimraf": "4.0.5", "@types/semver": "7.5.8", diff --git a/ts/components/menuAndSettingsHooks/useHideNoteToSelf.ts b/ts/components/menuAndSettingsHooks/useHideNoteToSelf.ts index 7bddaa0e4..c105611c4 100644 --- a/ts/components/menuAndSettingsHooks/useHideNoteToSelf.ts +++ b/ts/components/menuAndSettingsHooks/useHideNoteToSelf.ts @@ -1,7 +1,7 @@ -import { useDispatch } from 'react-redux'; import { useIsHidden, useIsMe } from '../../hooks/useParamSelector'; import { tr } from '../../localization/localeTools'; import { ConvoHub } from '../../session/conversations'; +import { getAppDispatch } from '../../state/dispatch'; import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { SessionButtonColor } from '../basic/SessionButton'; @@ -14,7 +14,7 @@ function useShowHideNoteToSelf({ conversationId }: { conversationId: string }) { export function useHideNoteToSelfCb({ conversationId }: { conversationId: string }) { const showHideNTS = useShowHideNoteToSelf({ conversationId }); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (!showHideNTS) { return null; diff --git a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts index 87a305cb7..4263183e8 100644 --- a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts +++ b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts @@ -12,18 +12,10 @@ function useShowNoteToSelf({ conversationId }: { conversationId: string }) { return isMe && isHidden; } -function useDispatch2() { - const dispatch = useDispatch(); - return { dispatch } -} export function useShowNoteToSelfCb({ conversationId }: { conversationId: string }) { const showNTS = useShowNoteToSelf({ conversationId }); - const { dispatch } = useDispatch2(); - - if (!showNTS) { - return null; - } + const dispatch = useDispatch(); const onClickClose = () => { dispatch(updateConfirmModal(null)); @@ -45,5 +37,10 @@ export function useShowNoteToSelfCb({ conversationId }: { conversationId: string }) ); }; + + if (!showNTS) { + return null; + } + return showConfirmationModal; } diff --git a/ts/state/createStore.ts b/ts/state/createStore.ts index 45bd9c96e..533fd6fc9 100644 --- a/ts/state/createStore.ts +++ b/ts/state/createStore.ts @@ -14,6 +14,7 @@ const persistConfig = { whitelist: ['userConfig'], }; +// @ts-expect-error -- FIXME const persistedReducer = persistReducer(persistConfig, rootReducer); const middlewareList = [promiseMiddleware]; @@ -28,3 +29,6 @@ export const createStore = (initialState: any) => immutableCheck: true, }).concat(middlewareList), }); + +export type AppDispatch = ReturnType['dispatch']; + diff --git a/ts/state/dispatch.ts b/ts/state/dispatch.ts new file mode 100644 index 000000000..cfade2530 --- /dev/null +++ b/ts/state/dispatch.ts @@ -0,0 +1,9 @@ +import { useDispatch } from 'react-redux'; +import type { AppDispatch } from './createStore'; + +export function getAppDispatch() { + // eslint-disable-next-line react-hooks/rules-of-hooks + const dispatch = useDispatch(); + return dispatch; +} + diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index 45abd442d..546433b78 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -78,3 +78,6 @@ const reducers = { // Making this work would require that our reducer signature supported AnyAction, not // our restricted actions export const rootReducer = combineReducers(reducers); + +export type RootState = ReturnType + diff --git a/yarn.lock b/yarn.lock index d75f43012..94061d624 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1684,15 +1684,17 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@reduxjs/toolkit@^1.9.7": - version "1.9.7" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.7.tgz#7fc07c0b0ebec52043f8cb43510cf346405f78a6" - integrity sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ== - dependencies: - immer "^9.0.21" - redux "^4.2.1" - redux-thunk "^2.4.2" - reselect "^4.1.8" +"@reduxjs/toolkit@^2.11.1": + version "2.11.1" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.11.1.tgz#69553cb3f7d60582c7a96682c381a38de98de9f4" + integrity sha512-HjhlEREguAyBTGNzRlGNiDHGQ2EjLSPWwdhhpoEqHYy8hWak3Dp6/fU72OfqVsiMb8S6rbfPsWUF24fxpilrVA== + dependencies: + "@standard-schema/spec" "^1.0.0" + "@standard-schema/utils" "^0.3.0" + immer "^11.0.0" + redux "^5.0.1" + redux-thunk "^3.1.0" + reselect "^5.1.0" "@rtsao/scc@^1.1.0": version "1.1.0" @@ -1740,6 +1742,16 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz#282046f03e886e352b2d5f5da5eb755e01457f3f" integrity sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA== +"@standard-schema/spec@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" + integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== + +"@standard-schema/utils@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@standard-schema/utils/-/utils-0.3.0.tgz#3d5e608f16c2390c10528e98e59aef6bf73cae7b" + integrity sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g== + "@szmarczak/http-timer@^4.0.5": version "4.0.6" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" @@ -1926,14 +1938,6 @@ dependencies: "@types/node" "*" -"@types/hoist-non-react-statics@^3.3.0": - version "3.3.5" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" - integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - "@types/http-cache-semantics@*": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" @@ -2065,16 +2069,6 @@ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c" integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== -"@types/react-redux@^7.1.33": - version "7.1.33" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" - integrity sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg== - dependencies: - "@types/hoist-non-react-statics" "^3.3.0" - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" - "@types/react-test-renderer@^18.3.1": version "18.3.1" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.3.1.tgz#225bfe8d4ad7ee3b04c2fa27642bb74274a5961d" @@ -5159,13 +5153,6 @@ help-me@^5.0.0: resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== -hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - hosted-git-info@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" @@ -5285,10 +5272,10 @@ image-type@^4.1.0: dependencies: file-type "^10.10.0" -immer@^9.0.21: - version "9.0.21" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" - integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== +immer@^11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-11.0.1.tgz#2191adadc17afc94553bfb7a4c0ca95e55ec2489" + integrity sha512-naDCyggtcBWANtIrjQEajhhBEuL9b0Zg4zmlWK2CzS6xCWSE39/vvf4LqnMjUAWHBhot4m9MHCM/Z+mfWhUkiA== immutable@^5.0.2: version "5.0.3" @@ -7376,7 +7363,7 @@ react-intersection-observer@^9.16.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -react-is@^16.13.1, react-is@^16.7.0: +react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -7391,7 +7378,7 @@ react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-redux@^9.0.0: +react-redux@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5" integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== @@ -7530,17 +7517,15 @@ redux-promise-middleware@^6.2.0: resolved "https://registry.yarnpkg.com/redux-promise-middleware/-/redux-promise-middleware-6.2.0.tgz#d139dfef50992d456860f8cf07a12085bd53f89d" integrity sha512-TEzfMeLX63gju2WqkdFQlQMvUGYzFvJNePIJJsBlbPHs3Txsbc/5Rjhmtha1XdMU6lkeiIlp1Qx7AR3Zo9he9g== -redux-thunk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b" - integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q== +redux-thunk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3" + integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw== -redux@4.2.1, redux@^4.0.0, redux@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" - integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== - dependencies: - "@babel/runtime" "^7.9.2" +redux@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: version "1.0.10" @@ -7638,10 +7623,10 @@ resedit@^1.7.0: dependencies: pe-library "^0.4.1" -reselect@^4.1.8: - version "4.1.8" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" - integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== +reselect@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e" + integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== resize-observer-polyfill@^1.5.1: version "1.5.1" From 1217c453365e82f45a3072f6f47a7444293381c5 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Wed, 10 Dec 2025 11:22:44 +1100 Subject: [PATCH 04/35] chore: improve babel output --- babel.config.js | 224 ++++++++++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 101 deletions(-) diff --git a/babel.config.js b/babel.config.js index 162240aa9..d1043a34f 100644 --- a/babel.config.js +++ b/babel.config.js @@ -21,7 +21,7 @@ const colors = { const sourceMapCache = new Map(); // Number of lines to show before/after error -const CONTEXT_LINES = 3; +const CONTEXT_LINES = 2; async function getOriginalLocation(jsFile, line, column) { try { @@ -66,122 +66,144 @@ function getSourceContent(jsFile) { module.exports = { presets: [ - ['@babel/preset-env', { - modules: 'commonjs', - targets: { - electron: '34', // or whatever version you're using + [ + '@babel/preset-env', + { + modules: 'commonjs', + targets: { + electron: '34', + }, }, - }], + ], ], plugins: [ - [require.resolve('babel-plugin-react-compiler'), { - target: '19', - logger: { - logEvent(filename, event) { - if (filename.includes('useAppDispatch')) { - console.log('Processing useAppDispatch:', event.kind); - } - - if (event.kind === 'CompileError') { - const debug = process.env.SESSION_RC_DEBUG; - if (!debug) { - return; - } - - const errorLoc = event.detail?.options?.loc; - const fnLoc = event.fnLoc; - const reason = event.detail?.options?.reason || 'Unknown error'; - const category = event.detail?.options?.category || 'Unknown'; - - (async () => { - console.log(`\n${colors.red}${colors.bright}[CompileError]${colors.reset} ${colors.cyan}${filename}${colors.reset}`); - console.log(` ${colors.yellow}Category:${colors.reset} ${category}`); - console.log(` ${colors.yellow}Reason:${colors.reset} ${reason}`); - - if (!fnLoc || !errorLoc) { + [ + require.resolve('babel-plugin-react-compiler'), + { + target: '19', + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + const debug = process.env.SESSION_RC_DEBUG; + if (!debug) { return; } - // Try to get original TS source from source map - const sourceData = getSourceContent(filename); - let source; let sourceName; - - if (sourceData) { - source = sourceData.content; - sourceName = sourceData.sourceName; - } else { - source = fs.readFileSync(filename, 'utf-8'); - sourceName = filename; - } - - const lines = source.split('\n'); - - // Map JS locations to TS locations - let errStartLine = errorLoc.start.line; - let errEndLine = errorLoc.end.line; - let errColStart = errorLoc.start.column; - let errColEnd = errorLoc.end.column; - - if (sourceData) { - const errStartOrig = await getOriginalLocation(filename, errorLoc.start.line, errorLoc.start.column); - const errEndOrig = await getOriginalLocation(filename, errorLoc.end.line, errorLoc.end.column); - - if (errStartOrig) { - errStartLine = errStartOrig.line; - errColStart = errStartOrig.column; + const errorLoc = event.detail?.options?.loc; + const fnLoc = event.fnLoc; + const reason = event.detail?.options?.reason || 'Unknown error'; + const category = event.detail?.options?.category || 'Unknown'; + + (async () => { + const outBuffer = []; + outBuffer.push( + `\n${colors.red}${colors.bright}[CompileError]${colors.reset} ${colors.cyan}${filename}${colors.reset}` + ); + outBuffer.push(` ${colors.yellow}Category:${colors.reset} ${category}`); + outBuffer.push(` ${colors.yellow}Reason:${colors.reset} ${reason}`); + + if (!fnLoc || !errorLoc) { + return; } - if (errEndOrig) { - errEndLine = errEndOrig.line; - errColEnd = errEndOrig.column; - } - } - - // Show context around the error - const contextStart = Math.max(0, errStartLine - CONTEXT_LINES - 1); - const contextEnd = Math.min(lines.length, errEndLine + CONTEXT_LINES); - console.log(` ${colors.yellow}Source:${colors.reset} ${colors.dim}${sourceName}${colors.reset}`); - console.log(` ${colors.yellow}Error at:${colors.reset} line ${errStartLine}, columns ${errColStart}-${errColEnd}`); - console.log(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + // Try to get original TS source from source map + const sourceData = getSourceContent(filename); + let source; + let sourceName; - for (let i = contextStart; i < contextEnd; i++) { - const lineNum = i + 1; - const lineNumStr = lineNum.toString().padStart(4, ' '); - const line = lines[i] || ''; - - const isErrorLine = lineNum >= errStartLine && lineNum <= errEndLine; - - if (isErrorLine) { - const gutter = `${colors.bgRed}${colors.white} ${lineNumStr} ${colors.reset}`; + if (sourceData) { + source = sourceData.content; + sourceName = sourceData.sourceName; + } else { + source = fs.readFileSync(filename, 'utf-8'); + sourceName = filename; + } - if (errColStart !== null && errColEnd !== null && lineNum === errStartLine) { - const before = line.substring(0, errColStart); - const highlight = line.substring(errColStart, errColEnd); - const after = line.substring(errColEnd); - console.log(` ${gutter} ${before}${colors.bgYellow}${colors.bright}${highlight}${colors.reset}${after}`); + const lines = source.split('\n'); + + // Map JS locations to TS locations + let errStartLine = errorLoc.start.line; + let errEndLine = errorLoc.end.line; + let errColStart = errorLoc.start.column; + let errColEnd = errorLoc.end.column; + + if (sourceData) { + const errStartOrig = await getOriginalLocation( + filename, + errorLoc.start.line, + errorLoc.start.column + ); + const errEndOrig = await getOriginalLocation( + filename, + errorLoc.end.line, + errorLoc.end.column + ); + + if (errStartOrig) { + errStartLine = errStartOrig.line; + errColStart = errStartOrig.column; + } + if (errEndOrig) { + errEndLine = errEndOrig.line; + errColEnd = errEndOrig.column; + } + } - const underline = ' '.repeat(errColStart) + '^'.repeat(Math.max(1, errColEnd - errColStart)); - console.log(` ${colors.dim} ${colors.reset} ${colors.red}${underline}${colors.reset}`); + // Show context around the error + const contextStart = Math.max(0, errStartLine - CONTEXT_LINES - 1); + const contextEnd = Math.min(lines.length, errEndLine + CONTEXT_LINES); + + outBuffer.push( + ` ${colors.yellow}Source:${colors.reset} ${colors.dim}${sourceName}${colors.reset}` + ); + outBuffer.push( + ` ${colors.yellow}Error at:${colors.reset} line ${errStartLine}, columns ${errColStart}-${errColEnd}` + ); + outBuffer.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + + for (let i = contextStart; i < contextEnd; i++) { + const lineNum = i + 1; + const lineNumStr = lineNum.toString().padStart(4, ' '); + const line = lines[i] || ''; + + const isErrorLine = lineNum >= errStartLine && lineNum <= errEndLine; + + if (isErrorLine) { + const gutter = `${colors.bgRed}${colors.white} ${lineNumStr} ${colors.reset}`; + + if (errColStart !== null && errColEnd !== null && lineNum === errStartLine) { + const before = line.substring(0, errColStart); + const highlight = line.substring(errColStart, errColEnd); + const after = line.substring(errColEnd); + outBuffer.push( + ` ${gutter} ${before}${colors.bgYellow}${colors.bright}${highlight}${colors.reset}${after}` + ); + + const underline = + ' '.repeat(errColStart) + '^'.repeat(Math.max(1, errColEnd - errColStart)); + outBuffer.push( + ` ${colors.dim} ${colors.reset} ${colors.red}${underline}${colors.reset}` + ); + } else { + outBuffer.push(` ${gutter} ${colors.red}${line}${colors.reset}`); + } } else { - console.log(` ${gutter} ${colors.red}${line}${colors.reset}`); + const gutter = `${colors.dim} ${lineNumStr} ${colors.reset}`; + outBuffer.push(` ${gutter} ${line}`); } - } else { - const gutter = `${colors.dim} ${lineNumStr} ${colors.reset}`; - console.log(` ${gutter} ${line}`); } - } - console.log(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); - })(); - } + outBuffer.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + + for (const line of outBuffer) { + console.log(line); + } + })(); + } + }, }, }, - }], - ], - only: [ - '**/ts/components/**', - '**/ts/components/*', - '**/ts/state/**', - '**/ts/state/*', + ], ], + only: ['**/ts/**'], }; From d1389c4d017895cd5d90f26f490d14adf2b71c28 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Wed, 10 Dec 2025 13:57:52 +1100 Subject: [PATCH 05/35] chore: babel react compiler error summary with files --- babel.config.js | 370 +++++++++++++++++++++++++++++++----------------- 1 file changed, 243 insertions(+), 127 deletions(-) diff --git a/babel.config.js b/babel.config.js index d1043a34f..0a8265b3d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,20 +1,30 @@ +/* eslint-disable no-console */ + const fs = require('fs'); +const path = require('path'); const { SourceMapConsumer } = require('source-map'); +const debug = process.env.SESSION_RC_DEBUG; + +// Project root directory (where babel.config.js lives) +const PROJECT_ROOT = __dirname; + // ANSI color codes +const c = (code) => process.env.NO_COLOR ? '' : `\x1b[${code}m`; const colors = { - reset: '\x1b[0m', - bright: '\x1b[1m', - dim: '\x1b[2m', - red: '\x1b[31m', - green: '\x1b[32m', - yellow: '\x1b[33m', - blue: '\x1b[34m', - magenta: '\x1b[35m', - cyan: '\x1b[36m', - white: '\x1b[37m', - bgRed: '\x1b[41m', - bgYellow: '\x1b[43m', + reset: c(0), + bright: c(1), + dim: c(2), + black: c(30), + red: c(31), + green: c(32), + yellow: c(33), + blue: c(34), + magenta: c(35), + cyan: c(36), + white: c(37), + bgRed: c(41), + bgYellow: c(43), }; // Cache for source map consumers @@ -23,6 +33,10 @@ const sourceMapCache = new Map(); // Number of lines to show before/after error const CONTEXT_LINES = 2; +// Collect all errors grouped by file +const errorsByFile = new Map(); +const pendingPromises = []; + async function getOriginalLocation(jsFile, line, column) { try { const mapFile = `${jsFile}.map`; @@ -64,6 +78,217 @@ function getSourceContent(jsFile) { } } +async function processErrorInternal(filename, event) { + const errorLoc = event.detail?.options?.loc; + const fnLoc = event.fnLoc; + const reason = event.detail?.options?.reason || 'Unknown error'; + const category = event.detail?.options?.category || 'Unknown'; + + const errorData = { + reason, + category, + lines: [], + }; + + if (!fnLoc || !errorLoc) { + errorData.lines.push(` ${colors.yellow}Reason:${colors.reset} [${category}] ${reason}`); + return errorData; + } + + // Try to get original TS source from source map + const sourceData = getSourceContent(filename); + let source; + let sourceName; + + if (sourceData) { + source = sourceData.content; + sourceName = sourceData.sourceName; + } else { + source = fs.readFileSync(filename, 'utf-8'); + sourceName = filename; + } + + const lines = source.split('\n'); + + // Map JS locations to TS locations + let errStartLine = errorLoc.start.line; + let errEndLine = errorLoc.end.line; + let errColStart = errorLoc.start.column; + let errColEnd = errorLoc.end.column; + + if (sourceData) { + const errStartOrig = await getOriginalLocation( + filename, + errorLoc.start.line, + errorLoc.start.column + ); + const errEndOrig = await getOriginalLocation( + filename, + errorLoc.end.line, + errorLoc.end.column + ); + + if (errStartOrig) { + errStartLine = errStartOrig.line; + errColStart = errStartOrig.column; + } + if (errEndOrig) { + errEndLine = errEndOrig.line; + errColEnd = errEndOrig.column; + } + } + + // Validate line numbers are within bounds + const maxLine = lines.length; + errStartLine = Math.max(1, Math.min(errStartLine, maxLine)); + errEndLine = Math.max(1, Math.min(errEndLine, maxLine)); + + // Show context around the error + const contextStart = Math.max(0, errStartLine - CONTEXT_LINES - 1); + const contextEnd = Math.min(lines.length, errEndLine + CONTEXT_LINES); + + errorData.sourceName = sourceName; + errorData.errStartLine = errStartLine; + errorData.errColStart = errColStart; + errorData.errColEnd = errColEnd; + + errorData.lines.push(` ${colors.yellow}Reason:${colors.reset} [${category}] ${reason}`); + errorData.lines.push( + ` ${colors.yellow}Source:${colors.reset} ${colors.dim}${sourceName}${colors.reset} line ${errStartLine}, columns ${errColStart}-${errColEnd}` + ); + + // Only show source context if we have valid lines to show + if (contextEnd > contextStart && lines.length > 0) { + errorData.lines.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + + for (let i = contextStart; i < contextEnd; i++) { + const lineNum = i + 1; + const lineNumStr = lineNum.toString().padStart(4, ' '); + const line = lines[i] ?? ''; + + const isErrorLine = lineNum >= errStartLine && lineNum <= errEndLine; + + if (isErrorLine) { + const gutter = `${colors.bgRed}${colors.black} ${lineNumStr} ${colors.reset}`; + + if (errColStart !== null && errColEnd !== null && lineNum === errStartLine) { + // Clamp column values to line length + const safeColStart = Math.min(errColStart, line.length); + const safeColEnd = Math.min(errColEnd, line.length); + + const before = line.substring(0, safeColStart); + const highlight = line.substring(safeColStart, safeColEnd); + const after = line.substring(safeColEnd); + + if (highlight.length > 0) { + errorData.lines.push( + ` ${gutter} ${before}${colors.bgYellow}${colors.black}${highlight}${colors.reset}${after}` + ); + + const underline = + ' '.repeat(safeColStart) + '^'.repeat(Math.max(1, safeColEnd - safeColStart)); + errorData.lines.push( + ` ${colors.dim} ${colors.reset} ${colors.red}${underline}${colors.reset}` + ); + } else { + // No highlight range, just show the line in red + errorData.lines.push(` ${gutter} ${colors.red}${line}${colors.reset}`); + } + } else { + errorData.lines.push(` ${gutter} ${colors.red}${line}${colors.reset}`); + } + } else { + const gutter = `${colors.dim} ${lineNumStr} ${colors.reset}`; + errorData.lines.push(` ${gutter} ${line}`); + } + } + + errorData.lines.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); + } else { + // No source context available + errorData.lines.push( + ` ${colors.dim}(source context not available - line ${errStartLine} may be out of range for file with ${lines.length} lines)${colors.reset}` + ); + } + + return errorData; +} + +async function processError(filename, event) { + const errorData = await processErrorInternal(filename, event) + if (!errorsByFile.has(filename)) { + errorsByFile.set(filename, []); + } + errorsByFile.get(filename).push(errorData); +} + +function printAllErrors() { + if (errorsByFile.size === 0) { + return; + } + + console.log(`\n${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}`); + console.log(`${colors.red}${colors.bright} REACT COMPILER ERRORS SUMMARY${colors.reset}`); + console.log(`${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}`); + + let totalErrors = 0; + + const errorsByFileArray = []; + errorsByFile.forEach((errors, filename) => { + const relativeFilename = path.relative(PROJECT_ROOT, filename); + totalErrors += errors.length; + errorsByFileArray.push({ errors, filename: relativeFilename }) + }); + + errorsByFileArray.sort((a, b) => b.errors.length - a.errors.length) + + errorsByFileArray.forEach(({ errors, filename }) => { + console.log( + `\n${colors.cyan}${colors.bright}📁 ${filename}${colors.reset} ${colors.dim}(${errors.length} error${errors.length > 1 ? 's' : ''})${colors.reset}` + ); + console.log(`${colors.dim}${'─'.repeat(70)}${colors.reset}`); + errors.forEach((error, index) => { + if (errors.length > 1) { + console.log(`\n ${colors.magenta}Error ${index + 1}:${colors.reset}`); + } + error.lines.forEach((line) => console.log(line)); + }); + }) + + const logTotals = () => { + console.log(`\n${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}`); + console.log( + `${colors.red}${colors.bright} Total: ${totalErrors} error${totalErrors > 1 ? 's' : ''} in ${errorsByFile.size} file${errorsByFile.size > 1 ? 's' : ''}${colors.reset}` + ); + console.log(`${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}\n`); + } + + console.log(`${colors.red} ${errorsByFile.size} files could not be compiled with the react compiler: ${colors.reset}`) + errorsByFileArray.forEach(({ filename, errors }) => console.log(` - (${errors.length}) ${colors.red}${colors.bright}${filename}${colors.reset}`)) + logTotals() + console.log(`${colors.red} Babel compilation complete with react compiler errors. Note: react compiler errors mean the file was not compiled with the react compiler, so is left in the same state it was in before compilation. ${colors.reset}\n`) +} + +async function handleErrorExit() { + await Promise.all(pendingPromises); + printAllErrors(); + if (errorsByFile.size > 0) { + process.exit(1); + } +} + +let cleanupRegistered = false; +function registerCleanup() { + if (cleanupRegistered) { + return; + } + cleanupRegistered = true; + + process.on('beforeExit', () => { + void handleErrorExit(); + }); +} + module.exports = { presets: [ [ @@ -83,122 +308,13 @@ module.exports = { target: '19', logger: { logEvent(filename, event) { + if (!debug) { + return; + } + if (event.kind === 'CompileError') { - const debug = process.env.SESSION_RC_DEBUG; - if (!debug) { - return; - } - - const errorLoc = event.detail?.options?.loc; - const fnLoc = event.fnLoc; - const reason = event.detail?.options?.reason || 'Unknown error'; - const category = event.detail?.options?.category || 'Unknown'; - - (async () => { - const outBuffer = []; - outBuffer.push( - `\n${colors.red}${colors.bright}[CompileError]${colors.reset} ${colors.cyan}${filename}${colors.reset}` - ); - outBuffer.push(` ${colors.yellow}Category:${colors.reset} ${category}`); - outBuffer.push(` ${colors.yellow}Reason:${colors.reset} ${reason}`); - - if (!fnLoc || !errorLoc) { - return; - } - - // Try to get original TS source from source map - const sourceData = getSourceContent(filename); - let source; - let sourceName; - - if (sourceData) { - source = sourceData.content; - sourceName = sourceData.sourceName; - } else { - source = fs.readFileSync(filename, 'utf-8'); - sourceName = filename; - } - - const lines = source.split('\n'); - - // Map JS locations to TS locations - let errStartLine = errorLoc.start.line; - let errEndLine = errorLoc.end.line; - let errColStart = errorLoc.start.column; - let errColEnd = errorLoc.end.column; - - if (sourceData) { - const errStartOrig = await getOriginalLocation( - filename, - errorLoc.start.line, - errorLoc.start.column - ); - const errEndOrig = await getOriginalLocation( - filename, - errorLoc.end.line, - errorLoc.end.column - ); - - if (errStartOrig) { - errStartLine = errStartOrig.line; - errColStart = errStartOrig.column; - } - if (errEndOrig) { - errEndLine = errEndOrig.line; - errColEnd = errEndOrig.column; - } - } - - // Show context around the error - const contextStart = Math.max(0, errStartLine - CONTEXT_LINES - 1); - const contextEnd = Math.min(lines.length, errEndLine + CONTEXT_LINES); - - outBuffer.push( - ` ${colors.yellow}Source:${colors.reset} ${colors.dim}${sourceName}${colors.reset}` - ); - outBuffer.push( - ` ${colors.yellow}Error at:${colors.reset} line ${errStartLine}, columns ${errColStart}-${errColEnd}` - ); - outBuffer.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); - - for (let i = contextStart; i < contextEnd; i++) { - const lineNum = i + 1; - const lineNumStr = lineNum.toString().padStart(4, ' '); - const line = lines[i] || ''; - - const isErrorLine = lineNum >= errStartLine && lineNum <= errEndLine; - - if (isErrorLine) { - const gutter = `${colors.bgRed}${colors.white} ${lineNumStr} ${colors.reset}`; - - if (errColStart !== null && errColEnd !== null && lineNum === errStartLine) { - const before = line.substring(0, errColStart); - const highlight = line.substring(errColStart, errColEnd); - const after = line.substring(errColEnd); - outBuffer.push( - ` ${gutter} ${before}${colors.bgYellow}${colors.bright}${highlight}${colors.reset}${after}` - ); - - const underline = - ' '.repeat(errColStart) + '^'.repeat(Math.max(1, errColEnd - errColStart)); - outBuffer.push( - ` ${colors.dim} ${colors.reset} ${colors.red}${underline}${colors.reset}` - ); - } else { - outBuffer.push(` ${gutter} ${colors.red}${line}${colors.reset}`); - } - } else { - const gutter = `${colors.dim} ${lineNumStr} ${colors.reset}`; - outBuffer.push(` ${gutter} ${line}`); - } - } - - outBuffer.push(` ${colors.dim}${'─'.repeat(60)}${colors.reset}`); - - for (const line of outBuffer) { - console.log(line); - } - })(); + registerCleanup(); + pendingPromises.push(processError(filename, event)); } }, }, From b6919308e96760ac4d9392186de4e956ebe76a99 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Wed, 10 Dec 2025 15:59:10 +1100 Subject: [PATCH 06/35] chore: change useDispatch to getAppDispatch --- babel.config.js | 53 ++++++++++----- ts/components/SessionSearchInput.tsx | 5 +- ts/components/basic/MessageBodyHighlight.tsx | 3 +- ts/components/buttons/HelpDeskButton.tsx | 4 +- ts/components/buttons/MenuButton.tsx | 4 +- ts/components/calling/CallButtons.tsx | 5 +- .../calling/CallInFullScreenContainer.tsx | 5 +- ts/components/conversation/Emojify.tsx | 3 +- ts/components/conversation/H5AudioPlayer.tsx | 5 +- .../conversation/SessionConversation.tsx | 4 +- .../SessionQuotedMessageComposition.tsx | 5 +- .../conversation/StagedAttachmentList.tsx | 4 +- .../conversation/TimerNotification.tsx | 4 +- .../header/ConversationHeader.tsx | 5 +- .../ConversationHeaderSelectionOverlay.tsx | 5 +- .../header/ConversationHeaderTitle.tsx | 4 +- .../media-gallery/AttachmentSection.tsx | 3 +- .../message-content/MessageAttachment.tsx | 5 +- .../message/message-content/MessageBody.tsx | 4 +- .../MessageContentWithStatus.tsx | 5 +- .../message-content/MessageContextMenu.tsx | 4 +- .../message-content/MessageLinkPreview.tsx | 4 +- .../message-item/ExpirableReadableMessage.tsx | 4 +- .../message/message-item/ReadableMessage.tsx | 5 +- .../right-panel/overlay/RightPanelMedia.tsx | 4 +- .../right-panel/overlay/components/Header.tsx | 4 +- .../message-info/OverlayMessageInfo.tsx | 7 +- ts/components/dialog/BanOrUnbanUserDialog.tsx | 4 +- ts/components/dialog/DeleteAccountModal.tsx | 4 +- .../dialog/EditProfilePictureModal.tsx | 4 +- ts/components/dialog/EnterPasswordModal.tsx | 4 +- .../dialog/HideRecoveryPasswordDialog.tsx | 4 +- ts/components/dialog/InviteContactsDialog.tsx | 4 +- ts/components/dialog/LocalizedPopupDialog.tsx | 4 +- ts/components/dialog/ModeratorsAddDialog.tsx | 4 +- .../dialog/ModeratorsRemoveDialog.tsx | 4 +- .../dialog/OnionStatusPathDialog.tsx | 4 +- ts/components/dialog/OpenUrlModal.tsx | 4 +- ts/components/dialog/QuitModal.tsx | 4 +- ts/components/dialog/ReactClearAllModal.tsx | 4 +- ts/components/dialog/ReactListModal.tsx | 6 +- ts/components/dialog/SessionCTA.tsx | 10 +-- ts/components/dialog/SessionConfirm.tsx | 4 +- .../dialog/SessionNicknameDialog.tsx | 4 +- .../dialog/TermsOfServicePrivacyDialog.tsx | 4 +- .../UpdateConversationDetailsDialog.tsx | 4 +- .../dialog/UpdateGroupMembersDialog.tsx | 6 +- ts/components/dialog/UserProfileModal.tsx | 4 +- .../blockOrUnblock/BlockOrUnblockDialog.tsx | 5 +- .../pages/conversationSettingsHooks.tsx | 4 +- .../DisappearingMessagesPage.tsx | 5 +- .../pages/notifications/NotificationPage.tsx | 4 +- ts/components/dialog/debug/DebugMenuModal.tsx | 4 +- ts/components/dialog/debug/FeatureFlags.tsx | 4 +- ts/components/dialog/debug/components.tsx | 6 +- .../dialog/debug/hooks/useReleaseChannel.tsx | 4 +- .../pages/AppearanceSettingsPage.tsx | 6 +- .../pages/BlockedContactsSettingsPage.tsx | 4 +- .../pages/ConversationSettingsPage.tsx | 5 +- .../pages/DefaultSettingsPage.tsx | 14 ++-- .../user-settings/pages/HelpSettingsPage.tsx | 4 +- .../pages/PrivacySettingsPage.tsx | 6 +- .../pages/RecoveryPasswordSettingsPage.tsx | 4 +- .../pages/network/SessionNetworkPage.tsx | 4 +- .../pages/network/sections/StakeSection.tsx | 4 +- .../sections/network/NetworkSection.tsx | 4 +- .../pages/user-pro/ProNonOriginatingPage.tsx | 12 ++-- .../pages/user-pro/ProSettingsPage.tsx | 20 +++--- .../user-settings/pages/userSettingsHooks.tsx | 6 +- ts/components/leftpane/ActionsPanel.tsx | 7 +- .../leftpane/LeftPaneMessageSection.tsx | 10 +-- .../leftpane/LeftPaneSectionHeader.tsx | 7 +- .../leftpane/overlay/OverlayClosedGroup.tsx | 5 +- .../leftpane/overlay/OverlayCommunity.tsx | 4 +- .../leftpane/overlay/OverlayInvite.tsx | 4 +- .../leftpane/overlay/OverlayMessage.tsx | 4 +- .../overlay/OverlayMessageRequest.tsx | 5 +- .../overlay/SessionJoinableDefaultRooms.tsx | 5 +- .../choose-action/OverlayChooseAction.tsx | 4 +- ts/components/lightbox/Lightbox.tsx | 4 +- ts/components/lightbox/LightboxGallery.tsx | 4 +- .../menu/ConversationListItemContextMenu.tsx | 3 +- ts/components/menu/Menu.tsx | 3 +- .../menu/MessageRequestBannerContextMenu.tsx | 7 +- .../CopyAccountId/CopyAccountIdMenuItem.tsx | 3 +- .../CopyCommunityUrlMenuItem.tsx | 3 +- .../menuAndSettingsHooks/useAddModerators.ts | 4 +- .../menuAndSettingsHooks/useBanUser.ts | 4 +- .../menuAndSettingsHooks/useChangeNickname.ts | 4 +- .../useClearAllMessages.ts | 4 +- .../useEditProfilePictureCallback.ts | 4 +- .../useProBadgeOnClickCb.tsx | 4 +- .../useRemoveModerators.ts | 4 +- .../useShowAttachments.ts | 4 +- .../useShowBlockUnblock.ts | 4 +- .../useShowConversationSettingsFor.ts | 4 +- .../useShowDeletePrivateContact.ts | 4 +- .../useShowDeletePrivateConversation.ts | 4 +- .../useShowInviteContactToCommunity.ts | 4 +- .../useShowInviteContactToGroup.ts | 4 +- .../useShowLeaveCommunity.ts | 4 +- .../menuAndSettingsHooks/useShowNoteToSelf.ts | 5 +- .../useShowUserDetailsCb.ts | 6 +- .../menuAndSettingsHooks/useUnbanUser.ts | 4 +- .../registration/RegistrationStages.tsx | 4 +- .../registration/TermsAndConditions.tsx | 4 +- .../registration/components/BackButton.tsx | 4 +- ts/components/registration/hooks/index.tsx | 4 +- .../registration/stages/CreateAccount.tsx | 4 +- .../registration/stages/RestoreAccount.tsx | 6 +- ts/components/registration/stages/Start.tsx | 4 +- ts/hooks/useAppFocused.ts | 5 +- ts/hooks/useCheckReleasedFeatures.ts | 4 +- ts/hooks/useHasPro.ts | 4 +- ts/hooks/useParamSelector.ts | 66 +++++++++++++++---- ts/hooks/usePasswordModal.ts | 4 +- ts/state/createStore.ts | 1 - ts/state/dispatch.ts | 1 - ts/state/reducer.ts | 3 +- ts/state/selectors/groups.ts | 2 +- ts/state/selectors/proBackendData.ts | 7 +- ts/state/selectors/selectedConversation.ts | 31 ++++++--- ts/state/selectors/userGroups.ts | 2 +- ts/types/Util.ts | 3 +- 124 files changed, 398 insertions(+), 312 deletions(-) diff --git a/babel.config.js b/babel.config.js index 0a8265b3d..ff5065b9f 100644 --- a/babel.config.js +++ b/babel.config.js @@ -5,12 +5,13 @@ const path = require('path'); const { SourceMapConsumer } = require('source-map'); const debug = process.env.SESSION_RC_DEBUG; +const fileFilter = process.env.SESSION_RC_FILE_FILTER; // Project root directory (where babel.config.js lives) const PROJECT_ROOT = __dirname; // ANSI color codes -const c = (code) => process.env.NO_COLOR ? '' : `\x1b[${code}m`; +const c = code => (process.env.NO_COLOR ? '' : `\x1b[${code}m`); const colors = { reset: c(0), bright: c(1), @@ -122,11 +123,7 @@ async function processErrorInternal(filename, event) { errorLoc.start.line, errorLoc.start.column ); - const errEndOrig = await getOriginalLocation( - filename, - errorLoc.end.line, - errorLoc.end.column - ); + const errEndOrig = await getOriginalLocation(filename, errorLoc.end.line, errorLoc.end.column); if (errStartOrig) { errStartLine = errStartOrig.line; @@ -215,7 +212,7 @@ async function processErrorInternal(filename, event) { } async function processError(filename, event) { - const errorData = await processErrorInternal(filename, event) + const errorData = await processErrorInternal(filename, event); if (!errorsByFile.has(filename)) { errorsByFile.set(filename, []); } @@ -237,12 +234,24 @@ function printAllErrors() { errorsByFile.forEach((errors, filename) => { const relativeFilename = path.relative(PROJECT_ROOT, filename); totalErrors += errors.length; - errorsByFileArray.push({ errors, filename: relativeFilename }) + errorsByFileArray.push({ errors, filename: relativeFilename }); }); - errorsByFileArray.sort((a, b) => b.errors.length - a.errors.length) + errorsByFileArray.sort((a, b) => b.errors.length - a.errors.length); + + if (fileFilter) { + console.log( + `${colors.red} File filter specified, filtering output for: ${fileFilter} ${colors.reset}` + ); + } + + let hiddenFiles = 0; errorsByFileArray.forEach(({ errors, filename }) => { + if (fileFilter && !filename.includes(fileFilter)) { + hiddenFiles++; + return; + } console.log( `\n${colors.cyan}${colors.bright}📁 ${filename}${colors.reset} ${colors.dim}(${errors.length} error${errors.length > 1 ? 's' : ''})${colors.reset}` ); @@ -251,9 +260,9 @@ function printAllErrors() { if (errors.length > 1) { console.log(`\n ${colors.magenta}Error ${index + 1}:${colors.reset}`); } - error.lines.forEach((line) => console.log(line)); + error.lines.forEach(line => console.log(line)); }); - }) + }); const logTotals = () => { console.log(`\n${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}`); @@ -261,12 +270,24 @@ function printAllErrors() { `${colors.red}${colors.bright} Total: ${totalErrors} error${totalErrors > 1 ? 's' : ''} in ${errorsByFile.size} file${errorsByFile.size > 1 ? 's' : ''}${colors.reset}` ); console.log(`${colors.red}${colors.bright}${'═'.repeat(70)}${colors.reset}\n`); - } + }; - console.log(`${colors.red} ${errorsByFile.size} files could not be compiled with the react compiler: ${colors.reset}`) - errorsByFileArray.forEach(({ filename, errors }) => console.log(` - (${errors.length}) ${colors.red}${colors.bright}${filename}${colors.reset}`)) - logTotals() - console.log(`${colors.red} Babel compilation complete with react compiler errors. Note: react compiler errors mean the file was not compiled with the react compiler, so is left in the same state it was in before compilation. ${colors.reset}\n`) + console.log( + `${colors.red} ${errorsByFile.size} files could not be compiled with the react compiler: ${colors.reset}` + ); + errorsByFileArray.forEach(({ filename, errors }) => + console.log(` - (${errors.length}) ${colors.red}${colors.bright}${filename}${colors.reset}`) + ); + logTotals(); + console.log( + `${colors.red} Babel compilation complete with react compiler errors. Note: react compiler errors mean the file was not compiled with the react compiler, so is left in the same state it was in before compilation. ${colors.reset}\n` + ); + + if (hiddenFiles > 0) { + console.log( + `${colors.red} ${hiddenFiles} files were hidden from the compiler output because of the filter: ${fileFilter} ${colors.reset}` + ); + } } async function handleErrorExit() { diff --git a/ts/components/SessionSearchInput.tsx b/ts/components/SessionSearchInput.tsx index 0fa4046d4..45a042929 100644 --- a/ts/components/SessionSearchInput.tsx +++ b/ts/components/SessionSearchInput.tsx @@ -1,8 +1,9 @@ import { Dispatch } from '@reduxjs/toolkit'; import { debounce } from 'lodash'; import { useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../state/dispatch'; import { searchActions, type DoSearchActionType, type SearchType } from '../state/ducks/search'; import { getConversationsCount } from '../state/selectors/conversations'; import { useLeftOverlayMode } from '../state/selectors/section'; @@ -64,7 +65,7 @@ function updateSearch(dispatch: Dispatch, searchOpts: DoSearchActionType) { export const SessionSearchInput = ({ searchType }: { searchType: SearchType }) => { const [currentSearchTerm, setCurrentSearchTerm] = useState(''); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isGroupCreationSearch = useLeftOverlayMode() === 'closed-group'; const convoCount = useSelector(getConversationsCount); diff --git a/ts/components/basic/MessageBodyHighlight.tsx b/ts/components/basic/MessageBodyHighlight.tsx index 93d4e70fe..52bab24f2 100644 --- a/ts/components/basic/MessageBodyHighlight.tsx +++ b/ts/components/basic/MessageBodyHighlight.tsx @@ -1,4 +1,5 @@ import styled from 'styled-components'; +import type { JSX } from 'react'; import { RenderTextCallbackType } from '../../types/Util'; import { SizeClassType } from '../../util/emoji'; import { AddNewLines } from '../conversation/AddNewLines'; @@ -8,8 +9,6 @@ import { renderTextDefault, } from '../conversation/message/message-content/MessageBody'; -import type { JSX } from "react"; - const renderNewLines: RenderTextCallbackType = ({ text, key, isGroup, isPublic }) => ( { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { const leftOverlayMode = useLeftOverlayMode(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isToggled = Boolean(leftOverlayMode); diff --git a/ts/components/calling/CallButtons.tsx b/ts/components/calling/CallButtons.tsx index 680d8317a..011edfd2f 100644 --- a/ts/components/calling/CallButtons.tsx +++ b/ts/components/calling/CallButtons.tsx @@ -1,7 +1,8 @@ import { MouseEvent, useEffect, useState } from 'react'; import { contextMenu, Menu } from 'react-contexify'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { CallManager, ToastUtils } from '../../session/utils'; import { InputItem } from '../../session/utils/calling/CallManager'; @@ -242,7 +243,7 @@ const StyledCallActionButton = styled.div<{ isFullScreen: boolean }>` `; const ShowInFullScreenButton = ({ isFullScreen }: { isFullScreen: boolean }) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const showInFullScreen = () => { if (isFullScreen) { diff --git a/ts/components/calling/CallInFullScreenContainer.tsx b/ts/components/calling/CallInFullScreenContainer.tsx index f855fb4da..aaa8ea259 100644 --- a/ts/components/calling/CallInFullScreenContainer.tsx +++ b/ts/components/calling/CallInFullScreenContainer.tsx @@ -1,8 +1,9 @@ import { useEffect, useRef } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { useVideoCallEventsListener } from '../../hooks/useVideoEventListener'; import { setFullScreenCall } from '../../state/ducks/call'; import { @@ -36,7 +37,7 @@ const StyledLocalVideoElement = styled.video<{ isVideoMuted: boolean }>` `; export const CallInFullScreenContainer = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const ongoingCallWithFocused = useSelector(getHasOngoingCallWithFocusedConvo); const hasOngoingCallFullScreen = useSelector(getCallIsInFullScreen); diff --git a/ts/components/conversation/Emojify.tsx b/ts/components/conversation/Emojify.tsx index 16295eb28..8b9111efc 100644 --- a/ts/components/conversation/Emojify.tsx +++ b/ts/components/conversation/Emojify.tsx @@ -1,9 +1,8 @@ +import type { JSX } from 'react'; import { SizeClassType } from '../../util/emoji'; import { RenderTextCallbackType } from '../../types/Util'; -import type { JSX } from "react"; - type Props = { text: string; /** A class name to be added to the generated emoji images */ diff --git a/ts/components/conversation/H5AudioPlayer.tsx b/ts/components/conversation/H5AudioPlayer.tsx index 00e3bf18e..8a6c0fa57 100644 --- a/ts/components/conversation/H5AudioPlayer.tsx +++ b/ts/components/conversation/H5AudioPlayer.tsx @@ -1,9 +1,10 @@ // Audio Player import { SessionDataTestId, useEffect, useRef, useState } from 'react'; import H5AudioPlayer, { RHAP_UI } from 'react-h5-audio-player'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; import { contextMenu } from 'react-contexify'; +import { getAppDispatch } from '../../state/dispatch'; import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch'; import { setNextMessageToPlayId } from '../../state/ducks/conversations'; import { useMessageDirection, useMessageSelected } from '../../state/selectors'; @@ -156,7 +157,7 @@ export const AudioPlayerWithEncryptedFile = (props: { messageId: string; }) => { const { messageId, contentType, src } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [playbackSpeed, setPlaybackSpeed] = useState(1.0); const { urlToLoad } = useEncryptedFileFetch(src, contentType, false); const player = useRef(null); diff --git a/ts/components/conversation/SessionConversation.tsx b/ts/components/conversation/SessionConversation.tsx index a712880b4..9ef57d15c 100644 --- a/ts/components/conversation/SessionConversation.tsx +++ b/ts/components/conversation/SessionConversation.tsx @@ -5,7 +5,7 @@ import autoBind from 'auto-bind'; import { blobToArrayBuffer } from 'blob-util'; import { Component, RefObject, createRef } from 'react'; import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { CompositionBox, SendMessageType, @@ -647,7 +647,7 @@ const renderImagePreview = async (contentType: string, file: File, fileName: str }; function OutdatedLegacyGroupBanner() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const weAreAdmin = useSelectedWeAreAdmin(); const selectedConversationKey = useSelectedConversationKey(); diff --git a/ts/components/conversation/SessionQuotedMessageComposition.tsx b/ts/components/conversation/SessionQuotedMessageComposition.tsx index 92ae2a9bc..19fcbd719 100644 --- a/ts/components/conversation/SessionQuotedMessageComposition.tsx +++ b/ts/components/conversation/SessionQuotedMessageComposition.tsx @@ -1,6 +1,7 @@ -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { quoteMessage } from '../../state/ducks/conversations'; import { getQuotedMessage } from '../../state/selectors/conversations'; @@ -67,7 +68,7 @@ function checkHasAttachments(attachments: Array | undefined) { } export const SessionQuotedMessageComposition = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const quotedMessageProps = useSelector(getQuotedMessage); const conversationId = useSelectedConversationKey(); diff --git a/ts/components/conversation/StagedAttachmentList.tsx b/ts/components/conversation/StagedAttachmentList.tsx index 2a32457b8..b560216d6 100644 --- a/ts/components/conversation/StagedAttachmentList.tsx +++ b/ts/components/conversation/StagedAttachmentList.tsx @@ -1,5 +1,5 @@ -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { removeAllStagedAttachmentsInConversation, removeStagedAttachmentInConversation, @@ -54,7 +54,7 @@ const StyledAttachmentsContainer = styled.div` export const StagedAttachmentList = (props: Props) => { const { attachments, onAddAttachment, onClickAttachment } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const conversationKey = useSelectedConversationKey(); const onRemoveAllStaged = () => { diff --git a/ts/components/conversation/TimerNotification.tsx b/ts/components/conversation/TimerNotification.tsx index ab0989b4f..fbca83d7a 100644 --- a/ts/components/conversation/TimerNotification.tsx +++ b/ts/components/conversation/TimerNotification.tsx @@ -1,7 +1,7 @@ -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import { PubkeyType } from 'libsession_util_nodejs'; import { isNil } from 'lodash'; +import { getAppDispatch } from '../../state/dispatch'; import { useSelectedConversationDisappearingMode, @@ -46,7 +46,7 @@ function useFollowSettingsButtonClick({ messageId }: WithMessageId) { const disabled = useMessageExpirationUpdateDisabled(messageId); const timespanText = useMessageExpirationUpdateTimespanText(messageId); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onExit = () => dispatch(updateConfirmModal(null)); const doIt = () => { diff --git a/ts/components/conversation/header/ConversationHeader.tsx b/ts/components/conversation/header/ConversationHeader.tsx index 00505e8c4..1590a048b 100644 --- a/ts/components/conversation/header/ConversationHeader.tsx +++ b/ts/components/conversation/header/ConversationHeader.tsx @@ -1,8 +1,7 @@ -import { useDispatch } from 'react-redux'; - import type { PubkeyType } from 'libsession_util_nodejs'; import { useCallback } from 'react'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../state/dispatch'; import { use05GroupMembers, @@ -108,7 +107,7 @@ const RecreateGroupContainer = styled.div` `; function useShowRecreateModal() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return useCallback( (name: string, members: Array) => { diff --git a/ts/components/conversation/header/ConversationHeaderSelectionOverlay.tsx b/ts/components/conversation/header/ConversationHeaderSelectionOverlay.tsx index 2deede209..925c1e497 100644 --- a/ts/components/conversation/header/ConversationHeaderSelectionOverlay.tsx +++ b/ts/components/conversation/header/ConversationHeaderSelectionOverlay.tsx @@ -1,6 +1,7 @@ import { useRef } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useKey from 'react-use/lib/useKey'; +import { getAppDispatch } from '../../../state/dispatch'; import { deleteMessagesForX } from '../../../interactions/conversations/unsendingInteractions'; import { resetSelectedMessageIds } from '../../../state/ducks/conversations'; @@ -24,7 +25,7 @@ export const SelectionOverlay = () => { const selectedMessageIds = useSelector(getSelectedMessageIds); const selectedConversationKey = useSelectedConversationKey(); const isPublic = useSelectedIsPublic(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const ref = useRef(null); function onCloseOverlay() { diff --git a/ts/components/conversation/header/ConversationHeaderTitle.tsx b/ts/components/conversation/header/ConversationHeaderTitle.tsx index f344efbb6..6d63d01e0 100644 --- a/ts/components/conversation/header/ConversationHeaderTitle.tsx +++ b/ts/components/conversation/header/ConversationHeaderTitle.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../state/dispatch'; import { useDisappearingMessageSettingText } from '../../../hooks/useParamSelector'; import { useIsRightPanelShowing } from '../../../hooks/useUI'; import { closeRightPanel } from '../../../state/ducks/conversations'; @@ -164,7 +164,7 @@ const StyledName = styled.span` `; export const ConversationHeaderTitle = ({ showSubtitle }: { showSubtitle: boolean }) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const convoId = useSelectedConversationKey(); const convoName = useSelectedNicknameOrProfileNameOrShortenedPubkey(); const isRightPanelOn = useIsRightPanelShowing(); diff --git a/ts/components/conversation/media-gallery/AttachmentSection.tsx b/ts/components/conversation/media-gallery/AttachmentSection.tsx index 22c6d2ba7..28cbaae67 100644 --- a/ts/components/conversation/media-gallery/AttachmentSection.tsx +++ b/ts/components/conversation/media-gallery/AttachmentSection.tsx @@ -1,11 +1,10 @@ import styled from 'styled-components'; +import type { JSX } from 'react'; import { missingCaseError } from '../../../util/missingCaseError'; import { MediaItemType } from '../../lightbox/LightboxGallery'; import { DocumentListItem } from './DocumentListItem'; import { MediaGridItem } from './MediaGridItem'; -import type { JSX } from "react"; - type Props = { type: 'media' | 'documents'; mediaItems: Array; diff --git a/ts/components/conversation/message/message-content/MessageAttachment.tsx b/ts/components/conversation/message/message-content/MessageAttachment.tsx index c4cef2515..d1107c9eb 100644 --- a/ts/components/conversation/message/message-content/MessageAttachment.tsx +++ b/ts/components/conversation/message/message-content/MessageAttachment.tsx @@ -1,7 +1,8 @@ import { clone } from 'lodash'; import { useCallback } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../state/dispatch'; import { Data } from '../../../../data/data'; import { MessageModelType, MessageRenderingProps } from '../../../../models/messageType'; import { PropsForAttachment, toggleSelectedMessageId } from '../../../../state/ducks/conversations'; @@ -59,7 +60,7 @@ export const MessageAttachment = (props: Props) => { const { messageId, imageBroken, handleImageError, highlight = false } = props; const isDetailView = useIsDetailMessageView(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const attachmentProps = useSelector((state: StateType) => getMessageAttachmentProps(state, messageId) ); diff --git a/ts/components/conversation/message/message-content/MessageBody.tsx b/ts/components/conversation/message/message-content/MessageBody.tsx index 0d9d7923c..46dc547c6 100644 --- a/ts/components/conversation/message/message-content/MessageBody.tsx +++ b/ts/components/conversation/message/message-content/MessageBody.tsx @@ -1,9 +1,9 @@ import LinkifyIt from 'linkify-it'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import type { ReactNode, JSX } from 'react'; +import { getAppDispatch } from '../../../../state/dispatch'; import { RenderTextCallbackType } from '../../../../types/Util'; import { getEmojiSizeClass, SizeClassType } from '../../../../util/emoji'; import { LinkPreviews } from '../../../../util/linkPreviews'; @@ -86,7 +86,7 @@ const Linkify = (props: LinkifyProps): JSX.Element => { const { text, isGroup, renderNonLink, isPublic } = props; const results: Array = []; let count = 1; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const matchData = linkify.match(text) || []; let last = 0; diff --git a/ts/components/conversation/message/message-content/MessageContentWithStatus.tsx b/ts/components/conversation/message/message-content/MessageContentWithStatus.tsx index 585bf1395..d88d28653 100644 --- a/ts/components/conversation/message/message-content/MessageContentWithStatus.tsx +++ b/ts/components/conversation/message/message-content/MessageContentWithStatus.tsx @@ -1,7 +1,8 @@ import { SessionDataTestId, MouseEvent, useCallback } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { clsx } from 'clsx'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../state/dispatch'; import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext'; import { replyToMessage } from '../../../../interactions/conversationInteractions'; import { MessageRenderingProps } from '../../../../models/messageType'; @@ -60,7 +61,7 @@ export const MessageContentWithStatuses = (props: Props) => { const contentProps = useSelector((state: StateType) => getMessageContentWithStatusesSelectorProps(state, props.messageId) ); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const hideAvatar = useHideAvatarInMsgList(props.messageId); const multiSelectMode = useIsMessageSelectionMode(); diff --git a/ts/components/conversation/message/message-content/MessageContextMenu.tsx b/ts/components/conversation/message/message-content/MessageContextMenu.tsx index 8b43c5a0d..9729f23dd 100644 --- a/ts/components/conversation/message/message-content/MessageContextMenu.tsx +++ b/ts/components/conversation/message/message-content/MessageContextMenu.tsx @@ -3,10 +3,10 @@ import { Dispatch, RefObject, useCallback, useEffect, useRef, useState } from 'r import { isNumber } from 'lodash'; import { ItemParams, Menu, useContextMenu } from 'react-contexify'; -import { useDispatch } from 'react-redux'; import useClickAway from 'react-use/lib/useClickAway'; import useMouse from 'react-use/lib/useMouse'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../state/dispatch'; import { Data } from '../../../../data/data'; import { MessageInteraction } from '../../../../interactions'; @@ -158,7 +158,7 @@ export const showMessageInfoOverlay = async ({ export const MessageContextMenu = (props: Props) => { const { messageId, contextMenuId, enableReactions } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { hideAll } = useContextMenu(); const isLegacyGroup = useSelectedIsLegacyGroup(); diff --git a/ts/components/conversation/message/message-content/MessageLinkPreview.tsx b/ts/components/conversation/message/message-content/MessageLinkPreview.tsx index 152920d65..e00b5bfdd 100644 --- a/ts/components/conversation/message/message-content/MessageLinkPreview.tsx +++ b/ts/components/conversation/message/message-content/MessageLinkPreview.tsx @@ -1,5 +1,5 @@ -import { useDispatch } from 'react-redux'; import clsx from 'clsx'; +import { getAppDispatch } from '../../../../state/dispatch'; import { MessageRenderingProps } from '../../../../models/messageType'; import { @@ -28,7 +28,7 @@ type Props = { const linkPreviewsImageSize = 100; export const MessageLinkPreview = (props: Props) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const direction = useMessageDirection(props.messageId); const attachments = useMessageAttachments(props.messageId); const previews = useMessageLinkPreview(props.messageId); diff --git a/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx b/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx index 5a4f2291c..a0368a985 100644 --- a/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx +++ b/ts/components/conversation/message/message-item/ExpirableReadableMessage.tsx @@ -1,8 +1,8 @@ import { useCallback } from 'react'; -import { useDispatch } from 'react-redux'; import useInterval from 'react-use/lib/useInterval'; import useMount from 'react-use/lib/useMount'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../state/dispatch'; import { useIsDetailMessageView } from '../../../../contexts/isDetailViewContext'; import { useMessageExpirationPropsById } from '../../../../hooks/useParamSelector'; import { MessageModelType } from '../../../../models/messageType'; @@ -23,7 +23,7 @@ function useIsExpired( ) { const { convoId, messageId, expirationDurationMs, expirationTimestamp, isExpired } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const checkExpired = useCallback(async () => { const now = Date.now(); diff --git a/ts/components/conversation/message/message-item/ReadableMessage.tsx b/ts/components/conversation/message/message-item/ReadableMessage.tsx index 057c03e37..7fd56bcd1 100644 --- a/ts/components/conversation/message/message-item/ReadableMessage.tsx +++ b/ts/components/conversation/message/message-item/ReadableMessage.tsx @@ -10,7 +10,8 @@ import { useState, } from 'react'; import { InView } from 'react-intersection-observer'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { useScrollToLoadedMessage } from '../../../../contexts/ScrollToLoadedMessage'; import { Data } from '../../../../data/data'; import { useHasUnread } from '../../../../hooks/useParamSelector'; @@ -108,7 +109,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => { } = props; const isAppFocused = useSelector(getIsAppFocused); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const selectedConversationKey = useSelectedConversationKey(); const mostRecentMessageId = useSelector(getMostRecentMessageId); diff --git a/ts/components/conversation/right-panel/overlay/RightPanelMedia.tsx b/ts/components/conversation/right-panel/overlay/RightPanelMedia.tsx index 2e214e8f6..2ee31a35b 100644 --- a/ts/components/conversation/right-panel/overlay/RightPanelMedia.tsx +++ b/ts/components/conversation/right-panel/overlay/RightPanelMedia.tsx @@ -1,7 +1,7 @@ import { compact, flatten, isEqual } from 'lodash'; import { useEffect, useState } from 'react'; -import { useDispatch } from 'react-redux'; import useInterval from 'react-use/lib/useInterval'; +import { getAppDispatch } from '../../../../state/dispatch'; import { Data } from '../../../../data/data'; @@ -95,7 +95,7 @@ async function getMediaGalleryProps(conversationId: string): Promise<{ export const RightPanelMedia = () => { const [documents, setDocuments] = useState>([]); const [media, setMedia] = useState>([]); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const selectedConvoKey = useSelectedConversationKey(); const isShowing = useIsRightPanelShowing(); diff --git a/ts/components/conversation/right-panel/overlay/components/Header.tsx b/ts/components/conversation/right-panel/overlay/components/Header.tsx index d0b6c596a..ee2294bd2 100644 --- a/ts/components/conversation/right-panel/overlay/components/Header.tsx +++ b/ts/components/conversation/right-panel/overlay/components/Header.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../../state/dispatch'; import { closeRightPanel } from '../../../../../state/ducks/conversations'; import { Flex } from '../../../../basic/Flex'; import { sectionActions } from '../../../../../state/ducks/section'; @@ -32,7 +32,7 @@ type HeaderProps = ( export const Header = (props: HeaderProps) => { const { children, hideCloseButton, closeButtonOnClick, paddingTop } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const rightOverlayMode = useRightOverlayMode(); const messageId = useSelector(getMessageInfoId); diff --git a/ts/components/dialog/BanOrUnbanUserDialog.tsx b/ts/components/dialog/BanOrUnbanUserDialog.tsx index f02c70db5..2295ec8ce 100644 --- a/ts/components/dialog/BanOrUnbanUserDialog.tsx +++ b/ts/components/dialog/BanOrUnbanUserDialog.tsx @@ -1,5 +1,5 @@ import { useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useFocusMount } from '../../hooks/useFocusMount'; import { useConversationUsernameWithFallback } from '../../hooks/useParamSelector'; @@ -70,7 +70,7 @@ export const BanOrUnBanUserDialog = (props: { }) => { const { conversationId, banType, pubkey } = props; const isBan = banType === 'ban'; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const convo = ConvoHub.use().get(conversationId); const inputRef = useRef(null); diff --git a/ts/components/dialog/DeleteAccountModal.tsx b/ts/components/dialog/DeleteAccountModal.tsx index 118e40d9f..7c538df6c 100644 --- a/ts/components/dialog/DeleteAccountModal.tsx +++ b/ts/components/dialog/DeleteAccountModal.tsx @@ -1,5 +1,5 @@ import { useCallback, useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { updateDeleteAccountModal } from '../../state/ducks/modalDialog'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; @@ -87,7 +87,7 @@ export const DeleteAccountModal = () => { const [askingConfirmation, setAskingConfirmation] = useState(false); const [deleteMode, setDeleteMode] = useState(DEVICE_ONLY); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onDeleteEverythingLocallyOnly = async () => { if (!isLoading) { diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index a4fc9c41f..3199a77a7 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; -import { useDispatch } from 'react-redux'; import type { AnyAction, Dispatch } from 'redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { ToastUtils, UserUtils } from '../../session/utils'; import { userSettingsModal, @@ -134,7 +134,7 @@ const triggerRemovalProfileAvatar = async (conversationId: string) => { }; export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureModalProps) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isMe = useIsMe(conversationId); const isCommunity = useIsPublic(conversationId); diff --git a/ts/components/dialog/EnterPasswordModal.tsx b/ts/components/dialog/EnterPasswordModal.tsx index ac21d2cf0..a81a8e93d 100644 --- a/ts/components/dialog/EnterPasswordModal.tsx +++ b/ts/components/dialog/EnterPasswordModal.tsx @@ -1,5 +1,5 @@ -import { useDispatch } from 'react-redux'; import { useState } from 'react'; +import { getAppDispatch } from '../../state/dispatch'; import { updateEnterPasswordModal } from '../../state/ducks/modalDialog'; import { SpacerSM } from '../basic/Text'; @@ -36,7 +36,7 @@ export const EnterPasswordModal = (props: EnterPasswordModalProps) => { const [password, setPassword] = useState(''); const [providedError, setProvidedError] = useState(undefined); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const verifyPassword = async () => { try { diff --git a/ts/components/dialog/HideRecoveryPasswordDialog.tsx b/ts/components/dialog/HideRecoveryPasswordDialog.tsx index 1e5e7e065..d89102c71 100644 --- a/ts/components/dialog/HideRecoveryPasswordDialog.tsx +++ b/ts/components/dialog/HideRecoveryPasswordDialog.tsx @@ -1,5 +1,5 @@ import { isEmpty } from 'lodash'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { SettingsKey } from '../../data/settings-key'; import { updateHideRecoveryPasswordModal, userSettingsModal } from '../../state/ducks/modalDialog'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; @@ -20,7 +20,7 @@ export type HideRecoveryPasswordDialogProps = { export function HideRecoveryPasswordDialog(props: HideRecoveryPasswordDialogProps) { const { state } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onClose = () => { dispatch(updateHideRecoveryPasswordModal(null)); diff --git a/ts/components/dialog/InviteContactsDialog.tsx b/ts/components/dialog/InviteContactsDialog.tsx index e53ae5449..e4dc4eb80 100644 --- a/ts/components/dialog/InviteContactsDialog.tsx +++ b/ts/components/dialog/InviteContactsDialog.tsx @@ -3,7 +3,7 @@ import useKey from 'react-use/lib/useKey'; import { clone } from 'lodash'; import { PubkeyType } from 'libsession_util_nodejs'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { ConvoHub } from '../../session/conversations'; import { updateGroupMembersModal, updateInviteContactModal } from '../../state/ducks/modalDialog'; import { SpacerLG } from '../basic/Text'; @@ -112,7 +112,7 @@ function ContactsToInvite({ const InviteContactsDialogInner = (props: Props) => { const { conversationId } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { contactsToInvite, isSearch, searchTerm, hasSearchResults } = useContactsToInviteTo( 'invite-contact-to', diff --git a/ts/components/dialog/LocalizedPopupDialog.tsx b/ts/components/dialog/LocalizedPopupDialog.tsx index 43b78097c..d3cf92b01 100644 --- a/ts/components/dialog/LocalizedPopupDialog.tsx +++ b/ts/components/dialog/LocalizedPopupDialog.tsx @@ -1,7 +1,7 @@ import { isEmpty } from 'lodash'; import { Dispatch } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { type LocalizedPopupDialogState, updateLocalizedPopupDialog, @@ -23,7 +23,7 @@ const StyledScrollDescriptionContainer = styled.div` `; export function LocalizedPopupDialog(props: LocalizedPopupDialogState) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); function onClose() { dispatch(updateLocalizedPopupDialog(null)); diff --git a/ts/components/dialog/ModeratorsAddDialog.tsx b/ts/components/dialog/ModeratorsAddDialog.tsx index c378486eb..a561f09c8 100644 --- a/ts/components/dialog/ModeratorsAddDialog.tsx +++ b/ts/components/dialog/ModeratorsAddDialog.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; import { compact } from 'lodash'; +import { getAppDispatch } from '../../state/dispatch'; import { sogsV3AddAdmin } from '../../session/apis/open_group_api/sogsv3/sogsV3AddRemoveMods'; import { PubKey } from '../../session/types'; @@ -29,7 +29,7 @@ type Props = { export const AddModeratorsDialog = (props: Props) => { const { conversationId } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const convo = ConvoHub.use().get(conversationId); const [inputBoxValue, setInputBoxValue] = useState(''); diff --git a/ts/components/dialog/ModeratorsRemoveDialog.tsx b/ts/components/dialog/ModeratorsRemoveDialog.tsx index 4def277ea..689338495 100644 --- a/ts/components/dialog/ModeratorsRemoveDialog.tsx +++ b/ts/components/dialog/ModeratorsRemoveDialog.tsx @@ -1,6 +1,6 @@ import { compact } from 'lodash'; import { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { ConvoHub } from '../../session/conversations'; import { PubKey } from '../../session/types'; @@ -61,7 +61,7 @@ export const RemoveModeratorsDialog = (props: Props) => { const { conversationId } = props; const [removingInProgress, setRemovingInProgress] = useState(false); const [modsToRemove, setModsToRemove] = useState>([]); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const closeDialog = () => { dispatch(updateRemoveModeratorsModal(null)); }; diff --git a/ts/components/dialog/OnionStatusPathDialog.tsx b/ts/components/dialog/OnionStatusPathDialog.tsx index 6f05354f2..77ac9e6db 100644 --- a/ts/components/dialog/OnionStatusPathDialog.tsx +++ b/ts/components/dialog/OnionStatusPathDialog.tsx @@ -1,7 +1,6 @@ import { ipcRenderer } from 'electron'; import { useState, SessionDataTestId, type JSX } from 'react'; -import { useDispatch } from 'react-redux'; import useHover from 'react-use/lib/useHover'; import styled from 'styled-components'; import useInterval from 'react-use/lib/useInterval'; @@ -9,6 +8,7 @@ import useInterval from 'react-use/lib/useInterval'; import { isEmpty, isTypedArray } from 'lodash'; import { CityResponse, Reader } from 'maxmind'; import useMount from 'react-use/lib/useMount'; +import { getAppDispatch } from '../../state/dispatch'; import { onionPathModal, updateOpenUrlModal } from '../../state/ducks/modalDialog'; import { useFirstOnionPath, @@ -249,7 +249,7 @@ function OnionPathDot({ } export const OnionPathModal = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { onClickOk, onClickCancel, i18nMessage } = props; const title = tr('warning'); diff --git a/ts/components/dialog/ReactClearAllModal.tsx b/ts/components/dialog/ReactClearAllModal.tsx index 270704f48..7c36c9d73 100644 --- a/ts/components/dialog/ReactClearAllModal.tsx +++ b/ts/components/dialog/ReactClearAllModal.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useMessageReactsPropsById } from '../../hooks/useParamSelector'; import { clearSogsReactionByServerId } from '../../session/apis/open_group_api/sogsv3/sogsV3ClearReaction'; import { ConvoHub } from '../../session/conversations'; @@ -25,7 +25,7 @@ export const ReactClearAllModal = (props: Props) => { const [clearingInProgress, setClearingInProgress] = useState(false); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const msgProps = useMessageReactsPropsById(messageId); if (!msgProps) { diff --git a/ts/components/dialog/ReactListModal.tsx b/ts/components/dialog/ReactListModal.tsx index 017345207..be8b5e952 100644 --- a/ts/components/dialog/ReactListModal.tsx +++ b/ts/components/dialog/ReactListModal.tsx @@ -1,7 +1,7 @@ import { isEmpty, isEqual } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { useMessageReactsPropsById } from '../../hooks/useParamSelector'; import { isUsAnySogsFromCache } from '../../session/apis/open_group_api/sogsv3/knownBlindedkeys'; import { UserUtils } from '../../session/utils'; @@ -97,7 +97,7 @@ type ReactionSendersProps = { const ReactionSenders = (props: ReactionSendersProps) => { const { messageId, currentReact, senders, me, conversationId } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const handleRemoveReaction = async () => { await Reactions.sendMessageReaction(messageId, currentReact); @@ -200,7 +200,7 @@ const handleSenders = (senders: Array, me: string) => { export const ReactListModal = (props: Props) => { const { reaction, messageId } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [reactions, setReactions] = useState([]); const [currentReact, setCurrentReact] = useState(''); diff --git a/ts/components/dialog/SessionCTA.tsx b/ts/components/dialog/SessionCTA.tsx index 7d6534897..02351f773 100644 --- a/ts/components/dialog/SessionCTA.tsx +++ b/ts/components/dialog/SessionCTA.tsx @@ -1,8 +1,8 @@ import { isNil } from 'lodash'; import { Dispatch, useMemo, type ReactNode } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import type { CSSProperties } from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { type SessionCTAState, updateSessionCTA, @@ -231,7 +231,7 @@ function Buttons({ afterActionButtonCallback?: () => void; actionButtonNextModalAfterCloseCallback?: () => void; }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const actionButton = useMemo(() => { if (!isVariantWithActionButton(variant)) { @@ -339,7 +339,7 @@ function Buttons({ } export function SessionCTA(props: SessionCTAState) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const hasPro = useCurrentUserHasPro(); function onClose() { @@ -393,7 +393,7 @@ export const showSessionCTA = (variant: CTAVariant, dispatch: Dispatch) => }; export const useShowSessionCTACb = (variant: CTAVariant) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); // TODO: remove once pro is released const isProAvailable = useIsProAvailable(); @@ -406,7 +406,7 @@ export const useShowSessionCTACb = (variant: CTAVariant) => { }; export const useShowSessionCTACbWithVariant = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); // TODO: remove once pro is released const isProAvailable = useIsProAvailable(); diff --git a/ts/components/dialog/SessionConfirm.tsx b/ts/components/dialog/SessionConfirm.tsx index e0c2a03c1..e046c6e17 100644 --- a/ts/components/dialog/SessionConfirm.tsx +++ b/ts/components/dialog/SessionConfirm.tsx @@ -1,6 +1,6 @@ -import { useDispatch } from 'react-redux'; import { useEffect, useState } from 'react'; import useKey from 'react-use/lib/useKey'; +import { getAppDispatch } from '../../state/dispatch'; import { useLastMessage } from '../../hooks/useParamSelector'; import { updateConversationInteractionState } from '../../interactions/conversationInteractions'; import { ConversationInteractionStatus } from '../../interactions/types'; @@ -63,7 +63,7 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => { conversationId, } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const lastMessage = useLastMessage(conversationId); const [isLoading, setIsLoading] = useState(false); diff --git a/ts/components/dialog/SessionNicknameDialog.tsx b/ts/components/dialog/SessionNicknameDialog.tsx index 9611c3ab1..1424c0be7 100644 --- a/ts/components/dialog/SessionNicknameDialog.tsx +++ b/ts/components/dialog/SessionNicknameDialog.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { ConvoHub } from '../../session/conversations'; import { changeNickNameModal } from '../../state/ducks/modalDialog'; @@ -64,7 +64,7 @@ export const SessionNicknameDialog = (props: Props) => { const { conversationId } = props; // this resolves to the real user name, and not the nickname (if set) like we do usually const displayName = useConversationRealName(conversationId); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const currentNickname = useNickname(conversationId); const [nickname, setStateNickname] = useState(currentNickname || ''); diff --git a/ts/components/dialog/TermsOfServicePrivacyDialog.tsx b/ts/components/dialog/TermsOfServicePrivacyDialog.tsx index a69b2d626..4e5b50471 100644 --- a/ts/components/dialog/TermsOfServicePrivacyDialog.tsx +++ b/ts/components/dialog/TermsOfServicePrivacyDialog.tsx @@ -1,5 +1,5 @@ import { shell } from 'electron'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { updateTermsOfServicePrivacyModal } from '../../state/onboarding/ducks/modals'; import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { @@ -18,7 +18,7 @@ export type TermsOfServicePrivacyDialogProps = { export function TermsOfServicePrivacyDialog(props: TermsOfServicePrivacyDialogProps) { const { show } = props; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onClose = () => { dispatch(updateTermsOfServicePrivacyModal(null)); diff --git a/ts/components/dialog/UpdateConversationDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx index 4c27dcdf0..67f2fc425 100644 --- a/ts/components/dialog/UpdateConversationDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; import useMount from 'react-use/lib/useMount'; import { isEmpty } from 'lodash'; +import { getAppDispatch } from '../../state/dispatch'; import { useAvatarPath, @@ -122,7 +122,7 @@ function useDescriptionErrorString({ } export function UpdateConversationDetailsDialog(props: WithConvoId) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { conversationId } = props; const isClosedGroup = useIsClosedGroup(conversationId); const isPublic = useIsPublic(conversationId); diff --git a/ts/components/dialog/UpdateGroupMembersDialog.tsx b/ts/components/dialog/UpdateGroupMembersDialog.tsx index 61133fd93..d8e4eed19 100644 --- a/ts/components/dialog/UpdateGroupMembersDialog.tsx +++ b/ts/components/dialog/UpdateGroupMembersDialog.tsx @@ -1,7 +1,7 @@ import { useMemo, useState } from 'react'; -import { useDispatch } from 'react-redux'; - import { PubkeyType } from 'libsession_util_nodejs'; +import { getAppDispatch } from '../../state/dispatch'; + import { ToastUtils } from '../../session/utils'; import { updateGroupMembersModal } from '../../state/ducks/modalDialog'; @@ -126,7 +126,7 @@ export const UpdateGroupMembersDialog = (props: Props) => { const { addTo, removeFrom, uniqueValues: membersToRemove } = useSet([]); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (isPrivate || isPublic) { throw new Error('UpdateGroupMembersDialog invalid convoProps'); diff --git a/ts/components/dialog/UserProfileModal.tsx b/ts/components/dialog/UserProfileModal.tsx index 34fdcf6e2..d0aaf5705 100644 --- a/ts/components/dialog/UserProfileModal.tsx +++ b/ts/components/dialog/UserProfileModal.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { ConvoHub } from '../../session/conversations'; import { openConversationWithMessages } from '../../state/ducks/conversations'; @@ -55,7 +55,7 @@ export const UserProfileModal = ({ conversationId, realSessionId, }: NonNullable) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [enlargedImage, setEnlargedImage] = useState(false); const isBlinded = PubKey.isBlinded(conversationId); diff --git a/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx b/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx index 94becccaa..91e4ef775 100644 --- a/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx +++ b/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx @@ -1,8 +1,7 @@ -import { useDispatch } from 'react-redux'; - import { isEmpty } from 'lodash'; import { useCallback } from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; +import { getAppDispatch } from '../../../state/dispatch'; import { useConversationsNicknameRealNameOrShortenPubkey } from '../../../hooks/useParamSelector'; import { updateBlockOrUnblockModal } from '../../../state/ducks/modalDialog'; import { BlockedNumberController } from '../../../util'; @@ -55,7 +54,7 @@ function useBlockUnblockI18nDescriptionArgs({ } export const BlockOrUnblockDialog = ({ pubkeys, action, onConfirmed }: NonNullable) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const localizedAction = action === 'block' ? tr('block') : tr('blockUnblock'); diff --git a/ts/components/dialog/conversationSettings/pages/conversationSettingsHooks.tsx b/ts/components/dialog/conversationSettings/pages/conversationSettingsHooks.tsx index eff62a199..170e870e7 100644 --- a/ts/components/dialog/conversationSettings/pages/conversationSettingsHooks.tsx +++ b/ts/components/dialog/conversationSettings/pages/conversationSettingsHooks.tsx @@ -1,5 +1,5 @@ import { noop } from 'lodash'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { tr } from '../../../../localization/localeTools'; import { ConversationSettingsModalPage, @@ -25,7 +25,7 @@ export function useTitleFromPage(page: ConversationSettingsModalPage | undefined } export function useCloseActionFromPage(props: ConversationSettingsModalState) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const showConvoSettingsCb = useShowConversationSettingsFor(props?.conversationId); if (!props?.conversationId || !showConvoSettingsCb) { return noop; diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx index 667fa84bf..5b8c70173 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../../../state/dispatch'; import { setDisappearingMessagesByConvoId } from '../../../../../interactions/conversationInteractions'; import { TimerOptions } from '../../../../../session/disappearing_messages/timerOptions'; import { DisappearingMessageConversationModeType } from '../../../../../session/disappearing_messages/types'; @@ -83,7 +84,7 @@ function useSingleMode(disappearingModeOptions: Record | undefi } export const DisappearingMessagesForConversationModal = (props: ConversationSettingsModalState) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onClose = useCloseActionFromPage(props); const title = useTitleFromPage(props?.settingsModalPage); const selectedConversationKey = useSelectedConversationKey(); diff --git a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx index 7050765cd..293b1a0b9 100644 --- a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../../state/dispatch'; import { useIsLegacyGroup, useNotificationSetting } from '../../../../../hooks/useParamSelector'; import { useSelectedConversationKey } from '../../../../../state/selectors/selectedConversation'; import { Flex } from '../../../../basic/Flex'; @@ -65,7 +65,7 @@ export function NotificationForConversationModal(props: Required) { } export function DebugMenuModal() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [page, setPage] = useState(DEBUG_MENU_PAGE.MAIN); diff --git a/ts/components/dialog/debug/FeatureFlags.tsx b/ts/components/dialog/debug/FeatureFlags.tsx index bada2f301..2e981ed80 100644 --- a/ts/components/dialog/debug/FeatureFlags.tsx +++ b/ts/components/dialog/debug/FeatureFlags.tsx @@ -1,9 +1,9 @@ import { isBoolean } from 'lodash'; import { Dispatch, useCallback, useEffect, useMemo, useState } from 'react'; import { clipboard } from 'electron'; -import { useDispatch } from 'react-redux'; import useAsync from 'react-use/lib/useAsync'; import { ProConfig, ProProof } from 'libsession_util_nodejs'; +import { getAppDispatch } from '../../../state/dispatch'; import { getDataFeatureFlag, getFeatureFlag, @@ -884,7 +884,7 @@ export const ProDebugSection = ({ forceUpdate, setPage, }: DebugMenuPageProps & { forceUpdate: () => void }) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const mockExpiry = useDataFeatureFlag('mockProAccessExpiry'); const proAvailable = useFeatureFlag('proAvailable'); diff --git a/ts/components/dialog/debug/components.tsx b/ts/components/dialog/debug/components.tsx index 2da464735..08dd3a8b4 100644 --- a/ts/components/dialog/debug/components.tsx +++ b/ts/components/dialog/debug/components.tsx @@ -1,7 +1,6 @@ import { base64_variants, from_hex, to_base64 } from 'libsodium-wrappers-sumo'; import useAsync from 'react-use/lib/useAsync'; import { ipcRenderer, shell } from 'electron'; -import { useDispatch } from 'react-redux'; import { useCallback, useState } from 'react'; import useAsyncFn from 'react-use/lib/useAsyncFn'; import useInterval from 'react-use/lib/useInterval'; @@ -10,6 +9,7 @@ import styled from 'styled-components'; import type { ProProof, PubkeyType } from 'libsession_util_nodejs'; import { chunk, toNumber } from 'lodash'; +import { getAppDispatch } from '../../../state/dispatch'; import { Flex } from '../../basic/Flex'; import { SpacerXS } from '../../basic/Text'; import { tr } from '../../../localization/localeTools'; @@ -330,7 +330,7 @@ export const Playgrounds = ({ setPage }: DebugMenuPageProps) => { }; export const DebugActions = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const proAvailable = useIsProAvailable(); return ( @@ -483,7 +483,7 @@ export const DebugUrlInteractionsSection = () => { }; export const ExperimentalActions = ({ forceUpdate }: { forceUpdate: () => void }) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); // const refreshedAt = useReleasedFeaturesRefreshedAt(); // const sesh101NotificationAt = useSesh101NotificationAt(); diff --git a/ts/components/dialog/debug/hooks/useReleaseChannel.tsx b/ts/components/dialog/debug/hooks/useReleaseChannel.tsx index 4bc418db6..0f57bdb00 100644 --- a/ts/components/dialog/debug/hooks/useReleaseChannel.tsx +++ b/ts/components/dialog/debug/hooks/useReleaseChannel.tsx @@ -1,5 +1,5 @@ -import { useDispatch } from 'react-redux'; import useUpdate from 'react-use/lib/useUpdate'; +import { getAppDispatch } from '../../../../state/dispatch'; import { tr } from '../../../../localization/localeTools'; import { Storage } from '../../../../util/storage'; import { updateConfirmModal } from '../../../../state/ducks/modalDialog'; @@ -14,7 +14,7 @@ export const useReleaseChannel = (): { setReleaseChannel: (channel: ReleaseChannels) => void; } => { const releaseChannel = Storage.get('releaseChannel') as ReleaseChannels; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const forceUpdate = useUpdate(); return { diff --git a/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx index 2ca35edcc..6c1abff20 100644 --- a/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx @@ -2,10 +2,10 @@ import useUpdate from 'react-use/lib/useUpdate'; import useInterval from 'react-use/lib/useInterval'; import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; import { isFinite, isNumber, range } from 'lodash'; import { contextMenu, Menu } from 'react-contexify'; import { useRef } from 'react'; +import { getAppDispatch } from '../../../../state/dispatch'; import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; import { @@ -61,7 +61,7 @@ const StyledPrimaryColorSwitcherContainer = styled.div` function PrimaryColorSwitcher() { const selectedPrimaryColor = usePrimaryColor(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const diameterRadioBorder = 35; return ( @@ -124,7 +124,7 @@ const StyledThemeName = styled.div` const Themes = () => { const themes = getThemeColors(); const selectedTheme = useTheme(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( <> diff --git a/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx index 16c5058a0..cd6f8b463 100644 --- a/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import useUpdate from 'react-use/lib/useUpdate'; import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { updateBlockOrUnblockModal, @@ -43,7 +43,7 @@ export function BlockedContactsSettingsPage(modalState: UserSettingsModalState) const backAction = useUserSettingsBackAction(modalState); const closeAction = useUserSettingsCloseAction(modalState); const title = useUserSettingsTitle(modalState); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [selectedIds, setSelectedIds] = useState>([]); async function unBlockThoseUsers() { diff --git a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx index 7ad2367e6..daef11023 100644 --- a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx @@ -1,5 +1,6 @@ import useUpdate from 'react-use/lib/useUpdate'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { userSettingsModal, @@ -40,7 +41,7 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { const backAction = useUserSettingsBackAction(modalState); const closeAction = useUserSettingsCloseAction(modalState); const title = useUserSettingsTitle(modalState); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isOpengroupPruningEnabled = Boolean( window.getSettingValue(SettingsKey.settingsOpengroupPruning) diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 3561c525d..1ab2ec6a0 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -1,7 +1,7 @@ import { type RefObject, useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import useMount from 'react-use/lib/useMount'; +import { getAppDispatch } from '../../../../state/dispatch'; import { useHotkey } from '../../../../hooks/useHotkey'; import { useOurConversationUsername, useOurAvatarPath } from '../../../../hooks/useParamSelector'; import { UserUtils, ToastUtils } from '../../../../session/utils'; @@ -98,7 +98,7 @@ function LucideIconForSettings(props: Omit @@ -238,7 +238,7 @@ function SettingsSection() { } function AdminSection() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const recoveryPasswordHidden = useHideRecoveryPasswordEnabled(); return ( @@ -302,7 +302,7 @@ const StyledSpanSessionInfo = styled.span<{ opacity?: number }>` const SessionInfo = () => { const [clickCount, setClickCount] = useState(0); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( @@ -348,7 +348,7 @@ const SessionInfo = () => { }; export const DefaultSettingPage = (modalState: UserSettingsModalState) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const closeAction = useUserSettingsCloseAction(modalState); const { refetch, t } = useProAccessDetails(); diff --git a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx index 25901c357..5b0e1d633 100644 --- a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { tr } from '../../../../localization/localeTools'; import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; @@ -22,7 +22,7 @@ export function HelpSettingsPage(modalState: UserSettingsModalState) { const closeAction = useUserSettingsCloseAction(modalState); const title = useUserSettingsTitle(modalState); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( void) } function HasPasswordSubSection() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( diff --git a/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx index 8bc45aea9..4bfd90da3 100644 --- a/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx @@ -1,6 +1,6 @@ -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import { useState } from 'react'; +import { getAppDispatch } from '../../../../state/dispatch'; import { updateHideRecoveryPasswordModal, @@ -72,7 +72,7 @@ export function RecoveryPasswordSettingsPage(modalState: UserSettingsModalState) const { dataURL, iconSize, iconColor, backgroundColor, loading } = useIconToImageURL(qrLogoProps); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { hasPassword, passwordValid } = usePasswordModal({ onClose: () => { diff --git a/ts/components/dialog/user-settings/pages/network/SessionNetworkPage.tsx b/ts/components/dialog/user-settings/pages/network/SessionNetworkPage.tsx index d12e01403..738bf51a7 100644 --- a/ts/components/dialog/user-settings/pages/network/SessionNetworkPage.tsx +++ b/ts/components/dialog/user-settings/pages/network/SessionNetworkPage.tsx @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../../state/dispatch'; import { ModalBasicHeader } from '../../../../SessionWrapperModal'; import { StakeSection } from './sections/StakeSection'; import { ExtraSmallText, LastRefreshedText } from './components'; @@ -23,7 +23,7 @@ import { ModalBackButton } from '../../../shared/ModalBackButton'; import { UserSettingsModalContainer } from '../../components/UserSettingsModalContainer'; function ReloadButton({ loading }: { loading: boolean }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { export function NetworkSection() { const htmlDirection = useHTMLDirection(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { swarmNodeCount, dataIsStale } = useSecuringNodesCount(); diff --git a/ts/components/dialog/user-settings/pages/user-pro/ProNonOriginatingPage.tsx b/ts/components/dialog/user-settings/pages/user-pro/ProNonOriginatingPage.tsx index ed537586a..442a06ad7 100644 --- a/ts/components/dialog/user-settings/pages/user-pro/ProNonOriginatingPage.tsx +++ b/ts/components/dialog/user-settings/pages/user-pro/ProNonOriginatingPage.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; import { type ReactNode } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../../state/dispatch'; import { tr } from '../../../../../localization/localeTools'; import { Localizer } from '../../../../basic/Localizer'; import { ModalBasicHeader } from '../../../../SessionWrapperModal'; @@ -221,7 +221,7 @@ function ProInfoBlockLayout({ } function ProInfoBlockUpgrade() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { data } = useProAccessDetails(); return ( { @@ -216,7 +216,7 @@ function useBackendErrorDialogButtons() { function ProNonProContinueButton({ state }: SectionProps) { const { returnToThisModalAction, centerAlign, afterCloseAction } = state; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const neverHadPro = useCurrentNeverHadPro(); const { isLoading, isError } = useProAccessDetails(); @@ -428,7 +428,7 @@ function ProStats() { } function ProSettings({ state }: SectionProps) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const userHasPro = useCurrentUserHasPro(); const userHasExpiredPro = useCurrentUserHasExpiredPro(); const userNeverHadPro = useCurrentNeverHadPro(); @@ -689,7 +689,7 @@ function getProFeatures(userHasPro: boolean): Array< } function ProFeatures({ state }: SectionProps) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const userHasPro = useCurrentUserHasPro(); const expiredPro = useCurrentUserHasExpiredPro(); const proFeatures = useMemo(() => getProFeatures(userHasPro), [userHasPro]); @@ -747,7 +747,7 @@ function ProFeatures({ state }: SectionProps) { } function ManageProCurrentAccess({ state }: SectionProps) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { data } = useProAccessDetails(); const userHasPro = useCurrentUserHasPro(); if (!userHasPro) { @@ -799,7 +799,7 @@ function ManageProCurrentAccess({ state }: SectionProps) { } function ManageProAccess({ state }: SectionProps) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isDarkTheme = useIsDarkTheme(); const userHasExpiredPro = useCurrentUserHasExpiredPro(); @@ -907,7 +907,7 @@ function ManageProRecoverAccess(_props: SectionProps) { } function ProHelp() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( @@ -937,7 +937,7 @@ function ProHelp() { } function PageHero({ state }: SectionProps) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPro = useCurrentUserHasPro(); const proExpired = useCurrentUserHasExpiredPro(); const { isLoading, isError } = useProAccessDetails(); @@ -1031,7 +1031,7 @@ export function ProSettingsPage(modalState: { centerAlign?: boolean; afterCloseAction?: () => void; }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const backAction = useUserSettingsBackAction(modalState); const closeAction = useUserSettingsCloseAction(modalState); diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index 2a2e15527..64ae50e84 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../../state/dispatch'; import { tr } from '../../../../localization/localeTools'; import { userSettingsModal, @@ -56,7 +56,7 @@ export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { } export function useUserSettingsCloseAction(props: UserSettingsModalState) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (!props?.userSettingsPage) { return null; } @@ -94,7 +94,7 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { } export function useUserSettingsBackAction(modalState: UserSettingsModalState) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (modalState?.overrideBackAction) { return modalState.overrideBackAction; diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 2f5d8994f..d45cc3ae5 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -1,13 +1,14 @@ import { ipcRenderer } from 'electron'; import { useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useInterval from 'react-use/lib/useInterval'; import useTimeoutFn from 'react-use/lib/useTimeoutFn'; import useMount from 'react-use/lib/useMount'; import useThrottleFn from 'react-use/lib/useThrottleFn'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { getOurPrimaryConversation, @@ -119,7 +120,7 @@ function useDebugThemeSwitch() { } function DebugMenuModalButton() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const debugMenuModalState = useDebugMenuModal(); useDebugKey({ @@ -148,7 +149,7 @@ function DebugMenuModalButton() { * The panel with buttons to switch between the message/contact/settings/theme views */ export const ActionsPanel = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [startCleanUpMedia, setStartCleanUpMedia] = useState(false); const ourPrimaryConversation = useSelector(getOurPrimaryConversation); const showDebugMenu = useDebugMode(); diff --git a/ts/components/leftpane/LeftPaneMessageSection.tsx b/ts/components/leftpane/LeftPaneMessageSection.tsx index e82fd0ad3..dc688c782 100644 --- a/ts/components/leftpane/LeftPaneMessageSection.tsx +++ b/ts/components/leftpane/LeftPaneMessageSection.tsx @@ -1,8 +1,10 @@ import { isEmpty } from 'lodash'; -import { useSelector, useDispatch } from 'react-redux'; - +import { useSelector } from 'react-redux'; import { AutoSizer, List, ListRowProps } from 'react-virtualized'; import styled from 'styled-components'; +import type { JSX } from 'react'; +import { getAppDispatch } from '../../state/dispatch'; + import { SearchResults } from '../search/SearchResults'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; import { MessageRequestsBanner } from './MessageRequestsBanner'; @@ -22,8 +24,6 @@ import { OverlayMessageRequest } from './overlay/OverlayMessageRequest'; import { OverlayChooseAction } from './overlay/choose-action/OverlayChooseAction'; import { sectionActions } from '../../state/ducks/section'; -import type { JSX } from "react"; - const StyledLeftPaneContent = styled.div` display: flex; flex-direction: column; @@ -121,7 +121,7 @@ const ConversationList = () => { export const LeftPaneMessageSection = () => { const leftOverlayMode = useLeftOverlayMode(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 120a530dd..9834b99ca 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -1,5 +1,6 @@ -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { LeftOverlayMode, sectionActions } from '../../state/ducks/section'; import { disableRecoveryPhrasePrompt } from '../../state/ducks/userConfig'; import { useLeftOverlayMode } from '../../state/selectors/section'; @@ -110,7 +111,7 @@ export const LeftPaneBanner = () => { const isSignInWithRecoveryPhrase = isSignWithRecoveryPhrase(); const hideRecoveryPassword = useHideRecoveryPasswordEnabled(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const showRecoveryPhraseModal = () => { dispatch(disableRecoveryPhrasePrompt()); @@ -161,7 +162,7 @@ export const LeftPaneSectionHeader = () => { const showRecoveryPhrasePrompt = useSelector(getShowRecoveryPhrasePrompt); const leftOverlayMode = useLeftOverlayMode(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const goBack = () => { if (!leftOverlayMode) { return; diff --git a/ts/components/leftpane/overlay/OverlayClosedGroup.tsx b/ts/components/leftpane/overlay/OverlayClosedGroup.tsx index 72ec3b0de..bdc9d8ca3 100644 --- a/ts/components/leftpane/overlay/OverlayClosedGroup.tsx +++ b/ts/components/leftpane/overlay/OverlayClosedGroup.tsx @@ -1,12 +1,13 @@ import { useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; import { concat, isEmpty } from 'lodash'; import useBoolean from 'react-use/lib/useBoolean'; import type { PubkeyType } from 'libsession_util_nodejs'; +import { getAppDispatch } from '../../../state/dispatch'; import { MemberListItem } from '../../MemberListItem'; import { SessionButton, SessionButtonColor } from '../../basic/SessionButton'; @@ -42,7 +43,7 @@ const StyledGroupMemberListContainer = styled.div` `; export const OverlayClosedGroupV2 = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const us = useOurPkStr(); const { contactsToInvite, searchTerm } = useContactsToInviteTo('create-group'); const isCreatingGroup = useIsCreatingGroupFromUIPending(); diff --git a/ts/components/leftpane/overlay/OverlayCommunity.tsx b/ts/components/leftpane/overlay/OverlayCommunity.tsx index 6e8ad4c52..dba69b0cf 100644 --- a/ts/components/leftpane/overlay/OverlayCommunity.tsx +++ b/ts/components/leftpane/overlay/OverlayCommunity.tsx @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; +import { getAppDispatch } from '../../../state/dispatch'; import { SessionJoinableRooms } from './SessionJoinableDefaultRooms'; @@ -44,7 +44,7 @@ async function joinOpenGroup( } export const OverlayCommunity = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [groupUrl, setGroupUrl] = useState(''); const [groupUrlError, setGroupUrlError] = useState(undefined); diff --git a/ts/components/leftpane/overlay/OverlayInvite.tsx b/ts/components/leftpane/overlay/OverlayInvite.tsx index a6663ac7f..304ac52bc 100644 --- a/ts/components/leftpane/overlay/OverlayInvite.tsx +++ b/ts/components/leftpane/overlay/OverlayInvite.tsx @@ -2,7 +2,7 @@ import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; import { useState } from 'react'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../../state/dispatch'; import { UserUtils } from '../../../session/utils'; import { Flex } from '../../basic/Flex'; import { SpacerLG, SpacerMD, SpacerSM } from '../../basic/Text'; @@ -61,7 +61,7 @@ export const OverlayInvite = () => { const [idCopied, setIdCopied] = useState(false); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); function closeOverlay() { dispatch(sectionActions.resetLeftOverlayMode()); diff --git a/ts/components/leftpane/overlay/OverlayMessage.tsx b/ts/components/leftpane/overlay/OverlayMessage.tsx index 1b11d1728..0f48e5fb0 100644 --- a/ts/components/leftpane/overlay/OverlayMessage.tsx +++ b/ts/components/leftpane/overlay/OverlayMessage.tsx @@ -4,8 +4,8 @@ import styled from 'styled-components'; import { motion } from 'framer-motion'; import { isEmpty } from 'lodash'; -import { useDispatch } from 'react-redux'; import { toASCII } from 'punycode'; +import { getAppDispatch } from '../../../state/dispatch'; import { ConvoHub } from '../../../session/conversations'; @@ -63,7 +63,7 @@ export const StyledLeftPaneOverlay = styled(Flex)` `; export const OverlayMessage = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); function closeOverlay() { dispatch(sectionActions.resetLeftOverlayMode()); diff --git a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx index ae91f325a..7dea29e0c 100644 --- a/ts/components/leftpane/overlay/OverlayMessageRequest.tsx +++ b/ts/components/leftpane/overlay/OverlayMessageRequest.tsx @@ -1,6 +1,7 @@ -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../state/dispatch'; import { declineConversationWithoutConfirm } from '../../../interactions/conversationInteractions'; import { updateConfirmModal } from '../../../state/ducks/modalDialog'; import { getConversationRequestsIds } from '../../../state/selectors/conversations'; @@ -51,7 +52,7 @@ const StyledLeftPaneOverlay = styled.div` export const OverlayMessageRequest = () => { useKey('Escape', closeOverlay); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); function closeOverlay() { dispatch(sectionActions.resetLeftOverlayMode()); diff --git a/ts/components/leftpane/overlay/SessionJoinableDefaultRooms.tsx b/ts/components/leftpane/overlay/SessionJoinableDefaultRooms.tsx index 4646bea52..4ccde60e5 100644 --- a/ts/components/leftpane/overlay/SessionJoinableDefaultRooms.tsx +++ b/ts/components/leftpane/overlay/SessionJoinableDefaultRooms.tsx @@ -1,7 +1,8 @@ import { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../state/dispatch'; import { parseOpenGroupV2 } from '../../../session/apis/open_group_api/opengroupV2/JoinOpenGroupV2'; import { fileDetailsToURL, @@ -28,7 +29,7 @@ export type JoinableRoomProps = WithRoomId & { }; const SessionJoinableRoomAvatar = (props: JoinableRoomProps) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); useEffect(() => { let isCancelled = false; diff --git a/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx b/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx index e8366e700..373fc8e41 100644 --- a/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx +++ b/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx @@ -1,8 +1,8 @@ import { useCallback, useEffect } from 'react'; import { isEmpty, isString } from 'lodash'; -import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; +import { getAppDispatch } from '../../../../state/dispatch'; import { SpacerSM } from '../../../basic/Text'; import { StyledLeftPaneOverlay } from '../OverlayMessage'; import { ActionRow, StyledActionRowContainer } from './ActionRow'; @@ -13,7 +13,7 @@ import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; import { tr } from '../../../../localization/localeTools'; export const OverlayChooseAction = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); function closeOverlay() { dispatch(sectionActions.resetLeftOverlayMode()); diff --git a/ts/components/lightbox/Lightbox.tsx b/ts/components/lightbox/Lightbox.tsx index 5d25646dd..483bc9173 100644 --- a/ts/components/lightbox/Lightbox.tsx +++ b/ts/components/lightbox/Lightbox.tsx @@ -1,9 +1,9 @@ import { CSSProperties, MouseEvent, MutableRefObject, useRef } from 'react'; import { isUndefined } from 'lodash'; -import { useDispatch } from 'react-redux'; import useUnmount from 'react-use/lib/useUnmount'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { useDisableDrag } from '../../hooks/useDisableDrag'; import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch'; import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; @@ -257,7 +257,7 @@ const LightboxObject = ({ export const Lightbox = (props: Props) => { const renderedRef = useRef(null); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const { caption, contentType, objectURL, onNext, onPrevious, onSave, onClose } = props; const onObjectClick = (event: any) => { diff --git a/ts/components/lightbox/LightboxGallery.tsx b/ts/components/lightbox/LightboxGallery.tsx index c5f756f71..5277757fc 100644 --- a/ts/components/lightbox/LightboxGallery.tsx +++ b/ts/components/lightbox/LightboxGallery.tsx @@ -1,8 +1,8 @@ import { useCallback, useState } from 'react'; -import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import useMount from 'react-use/lib/useMount'; +import { getAppDispatch } from '../../state/dispatch'; import { Lightbox } from './Lightbox'; import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; @@ -34,7 +34,7 @@ export const LightboxGallery = (props: Props) => { const [currentIndex, setCurrentIndex] = useState(selectedIndex); const selectedConversation = useSelectedConversationKey(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); // just run once, when the component is mounted. It's to show the lightbox on the specified index at start. useMount(() => { diff --git a/ts/components/menu/ConversationListItemContextMenu.tsx b/ts/components/menu/ConversationListItemContextMenu.tsx index 746a3dc4f..f0fb2cf40 100644 --- a/ts/components/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/menu/ConversationListItemContextMenu.tsx @@ -1,5 +1,6 @@ import { Menu } from 'react-contexify'; +import type { JSX } from 'react'; import { useConvoIdFromContext } from '../../contexts/ConvoIdContext'; import { useIsLegacyGroup, useIsPinned } from '../../hooks/useParamSelector'; import { useIsSearchingForType } from '../../state/selectors/search'; @@ -36,8 +37,6 @@ import { import { tr } from '../../localization/localeTools'; import { useTogglePinConversationHandler } from '../menuAndSettingsHooks/UseTogglePinConversationHandler'; -import type { JSX } from "react"; - export type PropsContextConversationItem = { triggerId: string; }; diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index dba99d5b6..2bb254cf3 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -1,4 +1,5 @@ import { Submenu } from 'react-contexify'; +import type { JSX } from 'react'; import { useConvoIdFromContext } from '../../contexts/ConvoIdContext'; import { useIsGroupV2, @@ -38,8 +39,6 @@ import { useChangeNickname } from '../menuAndSettingsHooks/useChangeNickname'; import { useShowNoteToSelfCb } from '../menuAndSettingsHooks/useShowNoteToSelf'; import { useShowUserDetailsCbFromConversation } from '../menuAndSettingsHooks/useShowUserDetailsCb'; -import type { JSX } from "react"; - /** Menu items standardized */ export const InviteContactMenuItem = (): JSX.Element | null => { diff --git a/ts/components/menu/MessageRequestBannerContextMenu.tsx b/ts/components/menu/MessageRequestBannerContextMenu.tsx index a3b165c55..5ed56e278 100644 --- a/ts/components/menu/MessageRequestBannerContextMenu.tsx +++ b/ts/components/menu/MessageRequestBannerContextMenu.tsx @@ -1,5 +1,6 @@ import { Menu } from 'react-contexify'; -import { useDispatch } from 'react-redux'; +import type { JSX } from 'react'; +import { getAppDispatch } from '../../state/dispatch'; import { SessionContextMenuContainer } from '../SessionContextMenuContainer'; @@ -8,14 +9,12 @@ import { ItemWithDataTestId } from './items/MenuItemWithDataTestId'; import { getMenuAnimation } from './MenuAnimation'; import { tr } from '../../localization/localeTools'; -import type { JSX } from "react"; - export type PropsContextConversationItem = { triggerId: string; }; const HideBannerMenuItem = (): JSX.Element => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { diff --git a/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx b/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx index 2c2b42dad..b70c66c52 100644 --- a/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx +++ b/ts/components/menu/items/CopyAccountId/CopyAccountIdMenuItem.tsx @@ -1,9 +1,8 @@ +import type { JSX } from 'react'; import { Localizer } from '../../../basic/Localizer'; import { useShowCopyAccountIdCb } from '../../../menuAndSettingsHooks/useCopyAccountId'; import { ItemWithDataTestId } from '../MenuItemWithDataTestId'; -import type { JSX } from "react"; - /** * Can be used to copy the conversation AccountID or the message's author sender'id. * Depending on what the pubkey is diff --git a/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx b/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx index a1851cb4a..3ab950b18 100644 --- a/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx +++ b/ts/components/menu/items/CopyCommunityUrl/CopyCommunityUrlMenuItem.tsx @@ -1,9 +1,8 @@ +import type { JSX } from 'react'; import { Localizer } from '../../../basic/Localizer'; import { useShowCopyCommunityUrlCb } from '../../../menuAndSettingsHooks/useCopyCommunityUrl'; import { ItemWithDataTestId } from '../MenuItemWithDataTestId'; -import type { JSX } from "react"; - export const CopyCommunityUrlMenuItem = ({ convoId }: { convoId: string }): JSX.Element | null => { const copyCommunityUrlCb = useShowCopyCommunityUrlCb(convoId); diff --git a/ts/components/menuAndSettingsHooks/useAddModerators.ts b/ts/components/menuAndSettingsHooks/useAddModerators.ts index 68e700825..ae7252c61 100644 --- a/ts/components/menuAndSettingsHooks/useAddModerators.ts +++ b/ts/components/menuAndSettingsHooks/useAddModerators.ts @@ -1,9 +1,9 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; import { updateAddModeratorsModal } from '../../state/ducks/modalDialog'; export function useAddModeratorsCb(conversationId: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); const weAreAdmin = useWeAreAdmin(conversationId); // only an admin can add moderators from a community. Another moderator cannot. diff --git a/ts/components/menuAndSettingsHooks/useBanUser.ts b/ts/components/menuAndSettingsHooks/useBanUser.ts index b7beb56a6..a1c98a9c7 100644 --- a/ts/components/menuAndSettingsHooks/useBanUser.ts +++ b/ts/components/menuAndSettingsHooks/useBanUser.ts @@ -1,10 +1,10 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPublic } from '../../hooks/useParamSelector'; import { updateBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; import { useWeAreCommunityAdminOrModerator } from '../../state/selectors/conversations'; export function useBanUserCb(conversationId?: string, pubkey?: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); const weAreCommunityAdminOrModerator = useWeAreCommunityAdminOrModerator(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useChangeNickname.ts b/ts/components/menuAndSettingsHooks/useChangeNickname.ts index 6b65f376d..f088dcd7f 100644 --- a/ts/components/menuAndSettingsHooks/useChangeNickname.ts +++ b/ts/components/menuAndSettingsHooks/useChangeNickname.ts @@ -1,9 +1,9 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsMe, useIsPrivate, useIsPrivateAndFriend } from '../../hooks/useParamSelector'; import { changeNickNameModal } from '../../state/ducks/modalDialog'; export function useChangeNickname(conversationId?: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isMe = useIsMe(conversationId); const isPrivate = useIsPrivate(conversationId); const isPrivateAndFriend = useIsPrivateAndFriend(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useClearAllMessages.ts b/ts/components/menuAndSettingsHooks/useClearAllMessages.ts index 14cf5f8a5..b52246411 100644 --- a/ts/components/menuAndSettingsHooks/useClearAllMessages.ts +++ b/ts/components/menuAndSettingsHooks/useClearAllMessages.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { deleteAllMessagesByConvoIdNoConfirmation } from '../../interactions/conversationInteractions'; import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { SessionButtonColor } from '../basic/SessionButton'; @@ -17,7 +17,7 @@ import { ToastUtils } from '../../session/utils'; import { groupInfoActions } from '../../state/ducks/metaGroups'; export function useClearAllMessagesCb({ conversationId }: { conversationId: string }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isKickedFromGroup = useIsKickedFromGroup(conversationId); const isMe = useIsMe(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useEditProfilePictureCallback.ts b/ts/components/menuAndSettingsHooks/useEditProfilePictureCallback.ts index da3cc449d..15fdd540e 100644 --- a/ts/components/menuAndSettingsHooks/useEditProfilePictureCallback.ts +++ b/ts/components/menuAndSettingsHooks/useEditProfilePictureCallback.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsGroupV2, useIsMe, useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; import { updateEditProfilePictureModal } from '../../state/ducks/modalDialog'; import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; @@ -23,7 +23,7 @@ function useEditProfilePicture({ conversationId }: { conversationId: string }) { export function useEditProfilePictureCallback({ conversationId }: { conversationId: string }) { const canEdit = useEditProfilePicture({ conversationId }); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (!canEdit) { return undefined; diff --git a/ts/components/menuAndSettingsHooks/useProBadgeOnClickCb.tsx b/ts/components/menuAndSettingsHooks/useProBadgeOnClickCb.tsx index 39457beef..6804fab9e 100644 --- a/ts/components/menuAndSettingsHooks/useProBadgeOnClickCb.tsx +++ b/ts/components/menuAndSettingsHooks/useProBadgeOnClickCb.tsx @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsProAvailable } from '../../hooks/useIsProAvailable'; import { ProMessageFeature } from '../../models/proMessageFeature'; import { SessionCTAState, updateSessionCTA } from '../../state/ducks/modalDialog'; @@ -121,7 +121,7 @@ function proFeatureToVariant(proFeature: ProMessageFeature): CTAVariant { export function useProBadgeOnClickCb( opts: ProBadgeContext ): ShowTagWithCb | ShowTagNoCb | DoNotShowTag { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const handleShowProInfoModal = useShowSessionCTACbWithVariant(); const isProAvailable = useIsProAvailable(); diff --git a/ts/components/menuAndSettingsHooks/useRemoveModerators.ts b/ts/components/menuAndSettingsHooks/useRemoveModerators.ts index b575dd71c..3637071a5 100644 --- a/ts/components/menuAndSettingsHooks/useRemoveModerators.ts +++ b/ts/components/menuAndSettingsHooks/useRemoveModerators.ts @@ -1,9 +1,9 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPublic, useWeAreAdmin } from '../../hooks/useParamSelector'; import { updateRemoveModeratorsModal } from '../../state/ducks/modalDialog'; export function useRemoveModeratorsCb(conversationId: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); const weAreAdmin = useWeAreAdmin(conversationId); // only an admin can remove moderators from a community. Another moderator cannot. diff --git a/ts/components/menuAndSettingsHooks/useShowAttachments.ts b/ts/components/menuAndSettingsHooks/useShowAttachments.ts index 6fb5bf937..1c39282d5 100644 --- a/ts/components/menuAndSettingsHooks/useShowAttachments.ts +++ b/ts/components/menuAndSettingsHooks/useShowAttachments.ts @@ -1,10 +1,10 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { updateConversationSettingsModal } from '../../state/ducks/modalDialog'; import { useIsKickedFromGroup } from '../../hooks/useParamSelector'; import { openRightPanel } from '../../state/ducks/conversations'; export function useShowAttachments({ conversationId }: { conversationId: string }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isKickedFromGroup = useIsKickedFromGroup(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useShowBlockUnblock.ts b/ts/components/menuAndSettingsHooks/useShowBlockUnblock.ts index 99d208655..244dfb8e6 100644 --- a/ts/components/menuAndSettingsHooks/useShowBlockUnblock.ts +++ b/ts/components/menuAndSettingsHooks/useShowBlockUnblock.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsMe, useIsBlocked, @@ -14,7 +14,7 @@ export function useShowBlockUnblock(convoId?: string) { const isBlocked = useIsBlocked(convoId); const isPrivate = useIsPrivate(convoId); const isIncomingRequest = useIsIncomingRequest(convoId); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const showBlockUnblock = convoId && !isMe && isPrivate && !isIncomingRequest && !PubKey.isBlinded(convoId); diff --git a/ts/components/menuAndSettingsHooks/useShowConversationSettingsFor.ts b/ts/components/menuAndSettingsHooks/useShowConversationSettingsFor.ts index 946377533..2875d815e 100644 --- a/ts/components/menuAndSettingsHooks/useShowConversationSettingsFor.ts +++ b/ts/components/menuAndSettingsHooks/useShowConversationSettingsFor.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPrivate, useIsPrivateAndFriend, @@ -10,7 +10,7 @@ import { } from '../../state/ducks/modalDialog'; export function useShowConversationSettingsFor(conversationId?: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPrivate = useIsPrivate(conversationId); const isPrivateAndFriend = useIsPrivateAndFriend(conversationId); const isLegacyGroup = useIsLegacyGroup(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useShowDeletePrivateContact.ts b/ts/components/menuAndSettingsHooks/useShowDeletePrivateContact.ts index 3fa1b2161..6c9aea4d9 100644 --- a/ts/components/menuAndSettingsHooks/useShowDeletePrivateContact.ts +++ b/ts/components/menuAndSettingsHooks/useShowDeletePrivateContact.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useConversationUsernameWithFallback, useIsIncomingRequest, @@ -20,7 +20,7 @@ function useShowDeletePrivateContact({ conversationId }: { conversationId: strin export function useShowDeletePrivateContactCb({ conversationId }: { conversationId: string }) { const showDeletePrivateContact = useShowDeletePrivateContact({ conversationId }); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const name = useConversationUsernameWithFallback(true, conversationId); if (!showDeletePrivateContact) { diff --git a/ts/components/menuAndSettingsHooks/useShowDeletePrivateConversation.ts b/ts/components/menuAndSettingsHooks/useShowDeletePrivateConversation.ts index f9d8ed372..e770a7e2c 100644 --- a/ts/components/menuAndSettingsHooks/useShowDeletePrivateConversation.ts +++ b/ts/components/menuAndSettingsHooks/useShowDeletePrivateConversation.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPrivate, useIsIncomingRequest, @@ -20,7 +20,7 @@ function useShowDeletePrivateConversation({ conversationId }: { conversationId: export function useShowDeletePrivateConversationCb({ conversationId }: { conversationId: string }) { const showDeletePrivateConversation = useShowDeletePrivateConversation({ conversationId }); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const name = useConversationUsernameWithFallback(true, conversationId); if (!showDeletePrivateConversation) { diff --git a/ts/components/menuAndSettingsHooks/useShowInviteContactToCommunity.ts b/ts/components/menuAndSettingsHooks/useShowInviteContactToCommunity.ts index 0ddc22019..eccd2cf57 100644 --- a/ts/components/menuAndSettingsHooks/useShowInviteContactToCommunity.ts +++ b/ts/components/menuAndSettingsHooks/useShowInviteContactToCommunity.ts @@ -1,9 +1,9 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { updateInviteContactModal } from '../../state/ducks/modalDialog'; import { useIsPublic } from '../../hooks/useParamSelector'; export function useShowInviteContactToCommunity(conversationId: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); const cb = () => dispatch(updateInviteContactModal({ conversationId })); diff --git a/ts/components/menuAndSettingsHooks/useShowInviteContactToGroup.ts b/ts/components/menuAndSettingsHooks/useShowInviteContactToGroup.ts index 382ffbbaa..33b80e53d 100644 --- a/ts/components/menuAndSettingsHooks/useShowInviteContactToGroup.ts +++ b/ts/components/menuAndSettingsHooks/useShowInviteContactToGroup.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsBlocked, useIsGroupDestroyed, @@ -9,7 +9,7 @@ import { import { updateInviteContactModal } from '../../state/ducks/modalDialog'; export function useShowInviteContactToGroupCb(conversationId: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isGroupV2 = useIsGroupV2(conversationId); const isBlocked = useIsBlocked(conversationId); const isKickedFromGroup = useIsKickedFromGroup(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useShowLeaveCommunity.ts b/ts/components/menuAndSettingsHooks/useShowLeaveCommunity.ts index 8fc8b9f70..128bbaf59 100644 --- a/ts/components/menuAndSettingsHooks/useShowLeaveCommunity.ts +++ b/ts/components/menuAndSettingsHooks/useShowLeaveCommunity.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useConversationUsernameWithFallback, useIsPublic } from '../../hooks/useParamSelector'; import { tr } from '../../localization/localeTools'; import { ConvoHub } from '../../session/conversations'; @@ -9,7 +9,7 @@ import { leaveGroupOrCommunityByConvoId } from '../../interactions/conversationI export function useShowLeaveCommunityCb(conversationId?: string) { const isPublic = useIsPublic(conversationId); const username = useConversationUsernameWithFallback(true, conversationId) || conversationId; - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); if (!isPublic || !conversationId) { return null; diff --git a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts index 4263183e8..8451d4a0f 100644 --- a/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts +++ b/ts/components/menuAndSettingsHooks/useShowNoteToSelf.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsHidden, useIsMe } from '../../hooks/useParamSelector'; import { ConvoHub } from '../../session/conversations'; import { updateConfirmModal } from '../../state/ducks/modalDialog'; @@ -12,10 +12,9 @@ function useShowNoteToSelf({ conversationId }: { conversationId: string }) { return isMe && isHidden; } - export function useShowNoteToSelfCb({ conversationId }: { conversationId: string }) { const showNTS = useShowNoteToSelf({ conversationId }); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const onClickClose = () => { dispatch(updateConfirmModal(null)); diff --git a/ts/components/menuAndSettingsHooks/useShowUserDetailsCb.ts b/ts/components/menuAndSettingsHooks/useShowUserDetailsCb.ts index ddbf4a867..5f0d90d03 100644 --- a/ts/components/menuAndSettingsHooks/useShowUserDetailsCb.ts +++ b/ts/components/menuAndSettingsHooks/useShowUserDetailsCb.ts @@ -1,4 +1,4 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { findCachedBlindedMatchOrLookItUp, getCachedNakedKeyFromBlindedNoServerPubkey, @@ -17,7 +17,7 @@ import { OpenGroupData } from '../../data/opengroups'; * Show the user details modal for a given message in the currently selected conversation. */ export function useShowUserDetailsCbFromMessage() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const selectedConvoKey = useSelectedConversationKey(); const isPublic = useIsPublic(selectedConvoKey); @@ -83,7 +83,7 @@ export function useShowUserDetailsCbFromConversation( conversationId?: string, allowForNts?: boolean ) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPrivate = useIsPrivate(conversationId); diff --git a/ts/components/menuAndSettingsHooks/useUnbanUser.ts b/ts/components/menuAndSettingsHooks/useUnbanUser.ts index cd408a73a..427d6e6b8 100644 --- a/ts/components/menuAndSettingsHooks/useUnbanUser.ts +++ b/ts/components/menuAndSettingsHooks/useUnbanUser.ts @@ -1,10 +1,10 @@ -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { useIsPublic } from '../../hooks/useParamSelector'; import { updateBanOrUnbanUserModal } from '../../state/ducks/modalDialog'; import { useWeAreCommunityAdminOrModerator } from '../../state/selectors/conversations'; export function useUnbanUserCb(conversationId?: string, pubkey?: string) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isPublic = useIsPublic(conversationId); const weAreCommunityAdminOrModerator = useWeAreCommunityAdminOrModerator(conversationId); diff --git a/ts/components/registration/RegistrationStages.tsx b/ts/components/registration/RegistrationStages.tsx index 1b6c35e69..8c13eb202 100644 --- a/ts/components/registration/RegistrationStages.tsx +++ b/ts/components/registration/RegistrationStages.tsx @@ -1,6 +1,6 @@ import { AnimatePresence } from 'framer-motion'; import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../../state/dispatch'; import { Data } from '../../data/data'; import { ConvoHub } from '../../session/conversations'; import { @@ -47,7 +47,7 @@ export const RegistrationStages = () => { const creationStep = useOnboardAccountCreationStep(); const restorationStep = useOnboardAccountRestorationStep(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( diff --git a/ts/components/registration/TermsAndConditions.tsx b/ts/components/registration/TermsAndConditions.tsx index 8d000cf5c..5db478fe5 100644 --- a/ts/components/registration/TermsAndConditions.tsx +++ b/ts/components/registration/TermsAndConditions.tsx @@ -1,5 +1,5 @@ -import { useDispatch } from 'react-redux'; import styled from 'styled-components'; +import { getAppDispatch } from '../../state/dispatch'; import { updateTermsOfServicePrivacyModal } from '../../state/onboarding/ducks/modals'; import { Localizer } from '../basic/Localizer'; @@ -17,7 +17,7 @@ const StyledTermsAndConditions = styled.div` `; export const TermsAndConditions = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return ( { const ourPubkey = useOnboardHexGeneratedPubKey(); const displayName = useDisplayName(); const progress = useProgress(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const recoveryComplete = useCallback(async () => { await finishRestore(ourPubkey, displayName); diff --git a/ts/components/registration/stages/CreateAccount.tsx b/ts/components/registration/stages/CreateAccount.tsx index 0a99a997f..cf24d573f 100644 --- a/ts/components/registration/stages/CreateAccount.tsx +++ b/ts/components/registration/stages/CreateAccount.tsx @@ -1,7 +1,7 @@ import { isEmpty } from 'lodash'; -import { useDispatch } from 'react-redux'; import useMount from 'react-use/lib/useMount'; import { useState } from 'react'; +import { getAppDispatch } from '../../../state/dispatch'; import { SettingsKey } from '../../../data/settings-key'; import { mnDecode } from '../../../session/crypto/mnemonic'; import { ProfileManager } from '../../../session/profile_manager/ProfileManager'; @@ -61,7 +61,7 @@ export const CreateAccount = () => { const displayName = useDisplayName(); const displayNameError = useDisplayNameError(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [cannotContinue, setCannotContinue] = useState(true); diff --git a/ts/components/registration/stages/RestoreAccount.tsx b/ts/components/registration/stages/RestoreAccount.tsx index b6f00c958..2558f8e6c 100644 --- a/ts/components/registration/stages/RestoreAccount.tsx +++ b/ts/components/registration/stages/RestoreAccount.tsx @@ -1,7 +1,7 @@ import { Dispatch } from '@reduxjs/toolkit'; import { isEmpty } from 'lodash'; -import { useDispatch } from 'react-redux'; import { useState } from 'react'; +import { getAppDispatch } from '../../../state/dispatch'; import { ONBOARDING_TIMES } from '../../../session/constants'; import { InvalidWordsError, NotEnoughWordsError } from '../../../session/crypto/mnemonic'; import { ProfileManager } from '../../../session/profile_manager/ProfileManager'; @@ -130,7 +130,7 @@ const showHideButtonDataTestIds = { } as const; const RecoveryPhraseInput = ({ onEnterPressed }: { onEnterPressed: () => Promise }) => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const recoveryPassword = useRecoveryPassword(); const recoveryPasswordError = useRecoveryPasswordError(); @@ -161,7 +161,7 @@ export const RestoreAccount = () => { const displayNameError = useDisplayNameError(); const progress = useProgress(); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const [cannotContinue, setCannotContinue] = useState(true); diff --git a/ts/components/registration/stages/Start.tsx b/ts/components/registration/stages/Start.tsx index cb2302a47..582b16c02 100644 --- a/ts/components/registration/stages/Start.tsx +++ b/ts/components/registration/stages/Start.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; -import { useDispatch } from 'react-redux'; import useMount from 'react-use/lib/useMount'; import styled from 'styled-components'; +import { getAppDispatch } from '../../../state/dispatch'; import { sleepFor } from '../../../session/utils/Promise'; import { AccountCreation, @@ -31,7 +31,7 @@ const StyledStart = styled.div<{ ready: boolean }>` export const Start = () => { const [ready, setReady] = useState(false); - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); useMount(() => { dispatch(resetOnboardingState()); diff --git a/ts/hooks/useAppFocused.ts b/ts/hooks/useAppFocused.ts index 202f43cd5..e4e5c1b36 100644 --- a/ts/hooks/useAppFocused.ts +++ b/ts/hooks/useAppFocused.ts @@ -1,6 +1,7 @@ import { ipcRenderer } from 'electron'; import { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; +import { getAppDispatch } from '../state/dispatch'; import { getIsAppFocused } from '../state/selectors/section'; import { sectionActions } from '../state/ducks/section'; @@ -9,7 +10,7 @@ import { sectionActions } from '../state/ducks/section'; * It sets up a listener for events from main_node.ts and update the global redux state with the focused state. */ export function useAppIsFocused() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const isFocusedFromStore = useSelector(getIsAppFocused); const ipcCallback = (_event: unknown, isFocused: unknown) => { diff --git a/ts/hooks/useCheckReleasedFeatures.ts b/ts/hooks/useCheckReleasedFeatures.ts index 0c4c2c271..a017cf604 100644 --- a/ts/hooks/useCheckReleasedFeatures.ts +++ b/ts/hooks/useCheckReleasedFeatures.ts @@ -1,11 +1,11 @@ import useInterval from 'react-use/lib/useInterval'; -import { useDispatch } from 'react-redux'; +import { getAppDispatch } from '../state/dispatch'; import { releasedFeaturesActions } from '../state/ducks/releasedFeatures'; import { NetworkTime } from '../util/NetworkTime'; import { FEATURE_RELEASE_CHECK_INTERVAL } from '../state/ducks/types/releasedFeaturesReduxTypes'; export function useCheckReleasedFeatures() { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); useInterval(() => { const nowFromNetwork = NetworkTime.now(); diff --git a/ts/hooks/useHasPro.ts b/ts/hooks/useHasPro.ts index c785dcae5..c0d96a3de 100644 --- a/ts/hooks/useHasPro.ts +++ b/ts/hooks/useHasPro.ts @@ -1,7 +1,7 @@ import { useCallback, useMemo } from 'react'; -import { useDispatch } from 'react-redux'; import { ProOriginatingPlatform } from 'libsession_util_nodejs'; import useUpdate from 'react-use/lib/useUpdate'; +import { getAppDispatch } from '../state/dispatch'; import { MockProAccessExpiryOptions, setDataFeatureFlag, @@ -221,7 +221,7 @@ function useMockRecoverAccess() { } export function useProAccessDetails(): RequestHook { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const setProBackendIsLoading = useSetProBackendIsLoading(); const setProBackendIsError = useSetProBackendIsError(); diff --git a/ts/hooks/useParamSelector.ts b/ts/hooks/useParamSelector.ts index c219d0d46..0109ed9db 100644 --- a/ts/hooks/useParamSelector.ts +++ b/ts/hooks/useParamSelector.ts @@ -17,13 +17,17 @@ import { getMessagePropsByMessageId, getMessageReactsProps, } from '../state/selectors/conversations'; -import { useLibGroupAdmins, useLibGroupMembers, useLibGroupName } from '../state/selectors/groups'; +import { + selectLibAdminsPubkeys, + selectLibGroupName, + useLibGroupMembers, +} from '../state/selectors/groups'; import { isPrivateAndFriend } from '../state/selectors/selectedConversation'; -import { useOurPkStr } from '../state/selectors/user'; +import { getOurNumber } from '../state/selectors/user'; import { + getGroupById, + getLibGroupKicked, useLibGroupDestroyed, - useLibGroupInvitePending, - useLibGroupKicked, } from '../state/selectors/userGroups'; import { ConversationInteractionStatus, ConversationInteractionType } from '../interactions/types'; import { tr } from '../localization/localeTools'; @@ -47,6 +51,11 @@ export function selectWeAreProUser(state: StateType) { ); } +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useLibGroupName(convoId?: string): string | undefined { + return useSelector((state: StateType) => selectLibGroupName(state, convoId)); +} + /** * Returns the nickname, the groupname or the displayNameInProfile of that conversation if set. */ @@ -227,9 +236,14 @@ export function useIsActive(convoId?: string) { return !!useActiveAt(convoId); } +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useLibGroupKickedInternal(convoId?: string) { + return useSelector((state: StateType) => getLibGroupKicked(state, convoId)); +} + export function useIsKickedFromGroup(convoId?: string) { const convoProps = useConversationPropsById(convoId); - const libIsKicked = useLibGroupKicked(convoId); + const libIsKicked = useLibGroupKickedInternal(convoId); if (convoId && PubKey.is03Pubkey(convoId)) { return libIsKicked ?? false; } @@ -244,10 +258,27 @@ export function useIsGroupDestroyed(convoId?: string) { return false; } -export function useWeAreAdmin(convoId?: string) { +function useIsAdmin(convoId?: string, pk?: string) { const groupAdmins = useGroupAdmins(convoId); - const us = useOurPkStr(); - return Boolean(groupAdmins.includes(us)); + // NOTE: [react-compiler] if we memoise this ourselves the compiler gets angry, but it will memoise it for us + const isAdmin = Boolean(pk && groupAdmins.includes(pk)); + return isAdmin; +} + +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useOurPkStrInternal() { + return useSelector((state: StateType) => getOurNumber(state)); +} + +export function useWeAreAdmin(convoId?: string) { + const us = useOurPkStrInternal(); + const isAdmin = useIsAdmin(convoId, us); + return isAdmin; +} + +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useLibGroupAdmins(convoId?: string): Array { + return useSelector((state: StateType) => selectLibAdminsPubkeys(state, convoId)); } export function useGroupAdmins(convoId?: string) { @@ -256,7 +287,8 @@ export function useGroupAdmins(convoId?: string) { const libMembers = useLibGroupAdmins(convoId); if (convoId && PubKey.is03Pubkey(convoId)) { - return compact(libMembers?.slice()?.sort()) || []; + const members = libMembers?.slice()?.sort() ?? []; + return compact(members); } return convoProps?.groupAdmins || []; @@ -292,12 +324,19 @@ export function useIsApproved(convoId?: string) { return Boolean(convoProps && convoProps.isApproved); } +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useLibGroupInvitePendingInternal(convoId?: string) { + return useSelector((state: StateType) => getGroupById(state, convoId)?.invitePending ?? false); +} + export function useIsIncomingRequest(convoId?: string) { const convoProps = useConversationPropsById(convoId); - const invitePending = useLibGroupInvitePending(convoId) || false; + const invitePending = useLibGroupInvitePendingInternal(convoId); + if (!convoProps) { return false; } + return Boolean( convoProps && hasValidIncomingRequestValues({ @@ -461,6 +500,11 @@ export function use05GroupMembers(convoId: string | undefined): Array void; onClose?: () => void; }) { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); const hashFromStorage = getPasswordHash(); const [hasPassword] = useState(!!hashFromStorage); diff --git a/ts/state/createStore.ts b/ts/state/createStore.ts index 533fd6fc9..f8b0a8d28 100644 --- a/ts/state/createStore.ts +++ b/ts/state/createStore.ts @@ -31,4 +31,3 @@ export const createStore = (initialState: any) => }); export type AppDispatch = ReturnType['dispatch']; - diff --git a/ts/state/dispatch.ts b/ts/state/dispatch.ts index cfade2530..51f4d2a79 100644 --- a/ts/state/dispatch.ts +++ b/ts/state/dispatch.ts @@ -6,4 +6,3 @@ export function getAppDispatch() { const dispatch = useDispatch(); return dispatch; } - diff --git a/ts/state/reducer.ts b/ts/state/reducer.ts index 546433b78..9dc26623e 100644 --- a/ts/state/reducer.ts +++ b/ts/state/reducer.ts @@ -79,5 +79,4 @@ const reducers = { // our restricted actions export const rootReducer = combineReducers(reducers); -export type RootState = ReturnType - +export type RootState = ReturnType; diff --git a/ts/state/selectors/groups.ts b/ts/state/selectors/groups.ts index 733565fb8..f270ed281 100644 --- a/ts/state/selectors/groups.ts +++ b/ts/state/selectors/groups.ts @@ -147,7 +147,7 @@ export function selectLibMembersCount(state: StateType, convo?: GroupPubkeyType) return selectLibMembersPubkeys(state, convo); } -function selectLibGroupName(state: StateType, convo?: string): string | undefined { +export function selectLibGroupName(state: StateType, convo?: string): string | undefined { if (!convo) { return undefined; } diff --git a/ts/state/selectors/proBackendData.ts b/ts/state/selectors/proBackendData.ts index 6316c6920..872ca7cc5 100644 --- a/ts/state/selectors/proBackendData.ts +++ b/ts/state/selectors/proBackendData.ts @@ -1,5 +1,6 @@ -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { useCallback } from 'react'; +import { getAppDispatch } from '../dispatch'; import type { StateType } from '../reducer'; import { proBackendDataActions, @@ -57,7 +58,7 @@ export const useProBackendCurrentUserStatus = () => { }; export const useSetProBackendIsLoading = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return useCallback( (props: RequestActionArgs) => dispatch(proBackendDataActions.setIsLoading(props)), [dispatch] @@ -65,7 +66,7 @@ export const useSetProBackendIsLoading = () => { }; export const useSetProBackendIsError = () => { - const dispatch = useDispatch(); + const dispatch = getAppDispatch(); return useCallback( (props: RequestActionArgs) => dispatch(proBackendDataActions.setIsError(props)), [dispatch] diff --git a/ts/state/selectors/selectedConversation.ts b/ts/state/selectors/selectedConversation.ts index dca3c7032..fb0128f7c 100644 --- a/ts/state/selectors/selectedConversation.ts +++ b/ts/state/selectors/selectedConversation.ts @@ -1,5 +1,4 @@ import { useSelector } from 'react-redux'; -import { useUnreadCount } from '../../hooks/useParamSelector'; import { isOpenOrClosedGroup } from '../../models/conversationAttributes'; import { ConversationTypeEnum } from '../../models/types'; import { @@ -13,9 +12,9 @@ import { getSelectedConversation, getSelectedMessageIds, } from './conversations'; -import { selectLibMembersPubkeys, useLibGroupName } from './groups'; +import { selectLibGroupName, selectLibMembersPubkeys } from './groups'; import { getCanWrite, getSubscriberCount } from './sogsRoomInfo'; -import { getLibGroupDestroyed, getLibGroupKicked, useLibGroupDestroyed } from './userGroups'; +import { getLibGroupDestroyed, getLibGroupKicked } from './userGroups'; import { tr } from '../../localization/localeTools'; const getIsSelectedPrivate = (state: StateType): boolean => { @@ -41,6 +40,20 @@ const getIsSelectedNoteToSelf = (state: StateType): boolean => { return getSelectedConversation(state)?.isMe || false; }; +const getSelectedUnreadCount = (state: StateType): number => { + return getSelectedConversation(state)?.unreadCount ?? 0; +}; + +const getSelectedLibGroupDestroyed = (state: StateType) => { + const selectedConversationId = getSelectedConversation(state)?.id; + return getLibGroupDestroyed(state, selectedConversationId); +}; + +const getSelectedGroupName = (state: StateType) => { + const selectedConversationId = getSelectedConversation(state)?.id; + return selectLibGroupName(state, selectedConversationId); +}; + export const getSelectedConversationKey = (state: StateType): string | undefined => { return state.conversations.selectedConversation; }; @@ -307,8 +320,7 @@ export function useSelectedIsActive() { } export function useSelectedUnreadCount() { - const selectedConversation = useSelectedConversationKey(); - return useUnreadCount(selectedConversation); + return useSelector(getSelectedUnreadCount); } export function useSelectedIsNoteToSelf() { @@ -334,8 +346,11 @@ export function useSelectedIsKickedFromGroup() { } export function useSelectedIsGroupDestroyed() { - const convoKey = useSelectedConversationKey(); - return useLibGroupDestroyed(convoKey); + return useSelector(getSelectedLibGroupDestroyed); +} + +export function useSelectedGroupName() { + return useSelector(getSelectedGroupName); } export function useSelectedExpireTimer(): number | undefined { @@ -384,7 +399,7 @@ export function useSelectedNicknameOrProfileNameOrShortenedPubkey() { const profileName = useSelectedDisplayNameInProfile(); const shortenedPubkey = useSelectedShortenedPubkeyOrFallback(); const isMe = useSelectedIsNoteToSelf(); - const libGroupName = useLibGroupName(selectedId); + const libGroupName = useSelectedGroupName(); if (isMe) { return tr('noteToSelf'); } diff --git a/ts/state/selectors/userGroups.ts b/ts/state/selectors/userGroups.ts index 42e385f9e..f33fb0145 100644 --- a/ts/state/selectors/userGroups.ts +++ b/ts/state/selectors/userGroups.ts @@ -6,7 +6,7 @@ import { StateType } from '../reducer'; const getUserGroupState = (state: StateType): UserGroupState => state.userGroups; -const getGroupById = (state: StateType, convoId?: string) => { +export const getGroupById = (state: StateType, convoId?: string) => { return convoId && PubKey.is03Pubkey(convoId) ? getUserGroupState(state).userGroups[convoId] : undefined; diff --git a/ts/types/Util.ts b/ts/types/Util.ts index e543f8812..71f9f0c3d 100644 --- a/ts/types/Util.ts +++ b/ts/types/Util.ts @@ -1,4 +1,5 @@ -import type { JSX } from "react"; +import type { JSX } from 'react'; + export type RenderTextCallbackType = (options: { text: string; key: number; From 199db439e42f1640cafb1415cf8482bfea808333 Mon Sep 17 00:00:00 2001 From: Ryan Miller Date: Thu, 11 Dec 2025 10:35:13 +1100 Subject: [PATCH 07/35] fix: turn feature flag hooks into getters --- ts/components/SessionPopover.tsx | 4 +- .../composition/CharacterCount.tsx | 4 +- .../dialog/EditProfilePictureModal.tsx | 4 +- .../dialog/OnionStatusPathDialog.tsx | 4 +- ts/components/dialog/SessionCTA.tsx | 6 +- .../UpdateConversationDetailsDialog.tsx | 3 +- ts/components/dialog/debug/FeatureFlags.tsx | 14 +- ts/components/dialog/debug/components.tsx | 6 +- .../debug/hooks/useDebugInputCommands.tsx | 4 +- .../debug/playgrounds/ProPlaygroundPage.tsx | 4 +- .../pages/DefaultSettingsPage.tsx | 4 +- .../pages/user-pro/ProSettingsPage.tsx | 14 +- ts/components/inputs/SessionInput.tsx | 233 ++------------ .../inputs/SimpleSessionTextarea.tsx | 190 ++++++++++++ ts/components/inputs/useUpdateInputValue.tsx | 16 + ts/components/leftpane/ActionsPanel.tsx | 8 +- .../leftpane/overlay/OverlayClosedGroup.tsx | 2 +- .../leftpane/overlay/OverlayCommunity.tsx | 2 +- .../leftpane/overlay/OverlayMessage.tsx | 2 +- .../UseTogglePinConversationHandler.tsx | 35 ++- .../useProBadgeOnClickCb.tsx | 4 +- .../useShowDeletePrivateContact.ts | 9 +- .../useShowDeletePrivateConversation.ts | 9 +- ts/hooks/useHasPro.ts | 286 ++++-------------- ts/hooks/useIsProAvailable.ts | 10 +- .../ducks/types/releasedFeaturesReduxTypes.ts | 14 +- ts/state/selectors/messages.ts | 4 +- ts/state/selectors/proBackendData.ts | 222 +++++++++++--- 28 files changed, 574 insertions(+), 543 deletions(-) create mode 100644 ts/components/inputs/SimpleSessionTextarea.tsx create mode 100644 ts/components/inputs/useUpdateInputValue.tsx diff --git a/ts/components/SessionPopover.tsx b/ts/components/SessionPopover.tsx index 7a5a95483..4ce0d0943 100644 --- a/ts/components/SessionPopover.tsx +++ b/ts/components/SessionPopover.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; import { type ReactNode, useMemo, useRef } from 'react'; -import { useFeatureFlag } from '../state/ducks/types/releasedFeaturesReduxTypes'; +import { getFeatureFlagMemo } from '../state/ducks/types/releasedFeaturesReduxTypes'; const TIP_LENGTH = 18; const VIEWPORT_MARGIN = 4; @@ -109,7 +109,7 @@ export const SessionPopoverContent = (props: PopoverProps) => { verticalPosition = 'top', } = props; - const showPopoverAnchors = useFeatureFlag('showPopoverAnchors'); + const showPopoverAnchors = getFeatureFlagMemo('showPopoverAnchors'); const ref = useRef(null); diff --git a/ts/components/conversation/composition/CharacterCount.tsx b/ts/components/conversation/composition/CharacterCount.tsx index 8d22af01f..873c60ef9 100644 --- a/ts/components/conversation/composition/CharacterCount.tsx +++ b/ts/components/conversation/composition/CharacterCount.tsx @@ -1,6 +1,6 @@ import styled from 'styled-components'; import { Constants } from '../../../session'; -import { useFeatureFlag } from '../../../state/ducks/types/releasedFeaturesReduxTypes'; +import { getFeatureFlagMemo } from '../../../state/ducks/types/releasedFeaturesReduxTypes'; import { SessionTooltip } from '../../SessionTooltip'; import { StyledCTA } from '../../basic/StyledCTA'; import { formatNumber } from '../../../util/i18n/formatting/generics'; @@ -52,7 +52,7 @@ function ProCta() { } export function CharacterCount({ count }: CharacterCountProps) { - const alwaysShowFlag = useFeatureFlag('alwaysShowRemainingChars'); + const alwaysShowFlag = getFeatureFlagMemo('alwaysShowRemainingChars'); const currentUserHasPro = useCurrentUserHasPro(); diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index 3199a77a7..4645a0074 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -29,7 +29,7 @@ import { ModalBasicHeader, SessionWrapperModal, } from '../SessionWrapperModal'; -import { useIsProAvailable } from '../../hooks/useIsProAvailable'; +import { getIsProAvailableMemo } from '../../hooks/useIsProAvailable'; import { SpacerLG, SpacerSM } from '../basic/Text'; import { AvatarSize } from '../avatar/Avatar'; import { ProIconButton } from '../buttons/ProButton'; @@ -139,7 +139,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo const isMe = useIsMe(conversationId); const isCommunity = useIsPublic(conversationId); const userHasPro = useUserHasPro(conversationId); - const isProAvailable = useIsProAvailable(); + const isProAvailable = getIsProAvailableMemo(); const avatarPath = useAvatarPath(conversationId) || ''; diff --git a/ts/components/dialog/OnionStatusPathDialog.tsx b/ts/components/dialog/OnionStatusPathDialog.tsx index 77ac9e6db..3886cb220 100644 --- a/ts/components/dialog/OnionStatusPathDialog.tsx +++ b/ts/components/dialog/OnionStatusPathDialog.tsx @@ -30,7 +30,7 @@ import { import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { ModalDescription } from './shared/ModalDescriptionContainer'; import { ModalFlexContainer } from './shared/ModalFlexContainer'; -import { useDataFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; +import { getDataFeatureFlagMemo } from '../../state/ducks/types/releasedFeaturesReduxTypes'; type StatusLightType = { glowing?: boolean; @@ -73,7 +73,7 @@ const StyledGrowingIcon = styled.div` function useOnionPathWithUsAndNetwork() { const onionPath = useFirstOnionPath(); - const localDevnet = useDataFeatureFlag('useLocalDevNet'); + const localDevnet = getDataFeatureFlagMemo('useLocalDevNet'); if (onionPath.length === 0) { return []; diff --git a/ts/components/dialog/SessionCTA.tsx b/ts/components/dialog/SessionCTA.tsx index 02351f773..b426063af 100644 --- a/ts/components/dialog/SessionCTA.tsx +++ b/ts/components/dialog/SessionCTA.tsx @@ -24,7 +24,7 @@ import { import { SpacerSM, SpacerXL } from '../basic/Text'; import type { MergedLocalizerTokens } from '../../localization/localeTools'; import { SessionButtonShiny } from '../basic/SessionButtonShiny'; -import { useIsProAvailable } from '../../hooks/useIsProAvailable'; +import { getIsProAvailableMemo } from '../../hooks/useIsProAvailable'; import { useCurrentUserHasPro } from '../../hooks/useHasPro'; import { assertUnreachable } from '../../types/sqlSharedTypes'; import { Storage } from '../../util/storage'; @@ -396,7 +396,7 @@ export const useShowSessionCTACb = (variant: CTAVariant) => { const dispatch = getAppDispatch(); // TODO: remove once pro is released - const isProAvailable = useIsProAvailable(); + const isProAvailable = getIsProAvailableMemo(); const isProCTA = useIsProCTAVariant(variant); if (isProCTA && !isProAvailable) { return () => null; @@ -409,7 +409,7 @@ export const useShowSessionCTACbWithVariant = () => { const dispatch = getAppDispatch(); // TODO: remove once pro is released - const isProAvailable = useIsProAvailable(); + const isProAvailable = getIsProAvailableMemo(); return (variant: CTAVariant) => { if (isProCTAVariant(variant) && !isProAvailable) { diff --git a/ts/components/dialog/UpdateConversationDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx index 67f2fc425..fdc4a1635 100644 --- a/ts/components/dialog/UpdateConversationDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -26,7 +26,7 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S import { SpacerMD, SpacerSM } from '../basic/Text'; import { SessionSpinner } from '../loading'; import { tr } from '../../localization/localeTools'; -import { SimpleSessionInput, SimpleSessionTextarea } from '../inputs/SessionInput'; +import { SimpleSessionInput } from '../inputs/SessionInput'; import { ModalBasicHeader, ModalActionsContainer, @@ -45,6 +45,7 @@ import { UploadFirstImageButton } from '../buttons/avatar/UploadFirstImageButton import { sanitizeDisplayNameOrToast } from '../registration/utils'; import { ProfileManager } from '../../session/profile_manager/ProfileManager'; import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes'; +import { SimpleSessionTextarea } from '../inputs/SimpleSessionTextarea'; /** * We want the description to be at most 200 visible characters, in addition diff --git a/ts/components/dialog/debug/FeatureFlags.tsx b/ts/components/dialog/debug/FeatureFlags.tsx index 2e981ed80..4b65d4c75 100644 --- a/ts/components/dialog/debug/FeatureFlags.tsx +++ b/ts/components/dialog/debug/FeatureFlags.tsx @@ -9,10 +9,10 @@ import { getFeatureFlag, MockProAccessExpiryOptions, SessionDataFeatureFlags, - useDataFeatureFlag, + getDataFeatureFlagMemo, type SessionDataFeatureFlagKeys, type SessionBooleanFeatureFlagKeys, - useFeatureFlag, + getFeatureFlagMemo, } from '../../../state/ducks/types/releasedFeaturesReduxTypes'; import { Flex } from '../../basic/Flex'; import { SessionToggle } from '../../basic/SessionToggle'; @@ -261,7 +261,7 @@ export const FlagIntegerInput = ({ visibleWithBooleanFlag, label, }: FlagIntegerInputProps) => { - const currentValue = useDataFeatureFlag(flag); + const currentValue = getDataFeatureFlagMemo(flag); const key = `feature-flag-integer-input-${flag}`; const [value, setValue] = useState(() => { const initValue = window.sessionDataFeatureFlags[flag]; @@ -624,8 +624,8 @@ export function FeatureFlagDumper({ forceUpdate }: { forceUpdate: () => void }) } function MessageProFeatures({ forceUpdate }: { forceUpdate: () => void }) { - const proIsAvailable = useFeatureFlag('proAvailable'); - const value = useDataFeatureFlag('mockMessageProFeatures') ?? []; + const proIsAvailable = getFeatureFlagMemo('proAvailable'); + const value = getDataFeatureFlagMemo('mockMessageProFeatures') ?? []; if (!proIsAvailable) { return null; @@ -885,8 +885,8 @@ export const ProDebugSection = ({ setPage, }: DebugMenuPageProps & { forceUpdate: () => void }) => { const dispatch = getAppDispatch(); - const mockExpiry = useDataFeatureFlag('mockProAccessExpiry'); - const proAvailable = useFeatureFlag('proAvailable'); + const mockExpiry = getDataFeatureFlagMemo('mockProAccessExpiry'); + const proAvailable = getFeatureFlagMemo('proAvailable'); const resetPro = useCallback(async () => { await UserConfigWrapperActions.removeProConfig(); diff --git a/ts/components/dialog/debug/components.tsx b/ts/components/dialog/debug/components.tsx index 08dd3a8b4..f34465a05 100644 --- a/ts/components/dialog/debug/components.tsx +++ b/ts/components/dialog/debug/components.tsx @@ -59,7 +59,7 @@ import { import { formatRoundedUpTimeUntilTimestamp } from '../../../util/i18n/formatting/generics'; import { LucideIcon } from '../../icon/LucideIcon'; import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; -import { useIsProAvailable } from '../../../hooks/useIsProAvailable'; +import { getIsProAvailableMemo } from '../../../hooks/useIsProAvailable'; type DebugButtonProps = SessionButtonProps & { shiny?: boolean; hide?: boolean }; @@ -315,7 +315,7 @@ export const LoggingDebugSection = ({ forceUpdate }: { forceUpdate: () => void } }; export const Playgrounds = ({ setPage }: DebugMenuPageProps) => { - const proAvailable = useIsProAvailable(); + const proAvailable = getIsProAvailableMemo(); if (!proAvailable) { return null; @@ -331,7 +331,7 @@ export const Playgrounds = ({ setPage }: DebugMenuPageProps) => { export const DebugActions = () => { const dispatch = getAppDispatch(); - const proAvailable = useIsProAvailable(); + const proAvailable = getIsProAvailableMemo(); return ( diff --git a/ts/components/dialog/debug/hooks/useDebugInputCommands.tsx b/ts/components/dialog/debug/hooks/useDebugInputCommands.tsx index 7e9243cdb..b0042dd87 100644 --- a/ts/components/dialog/debug/hooks/useDebugInputCommands.tsx +++ b/ts/components/dialog/debug/hooks/useDebugInputCommands.tsx @@ -1,7 +1,7 @@ import { type Dispatch, useEffect } from 'react'; import { isDevProd } from '../../../../shared/env_vars'; import { Constants } from '../../../../session'; -import { useFeatureFlag } from '../../../../state/ducks/types/releasedFeaturesReduxTypes'; +import { getFeatureFlagMemo } from '../../../../state/ducks/types/releasedFeaturesReduxTypes'; type DebugInputCommandsArgs = { value: string; @@ -25,7 +25,7 @@ export function useDebugInputCommands({ value, setValue }: DebugInputCommandsArg } // eslint-disable-next-line react-hooks/rules-of-hooks -- Conditional doesn't change at runtime - const debugInputCommands = useFeatureFlag('debugInputCommands'); + const debugInputCommands = getFeatureFlagMemo('debugInputCommands'); // eslint-disable-next-line react-hooks/rules-of-hooks useEffect(() => { diff --git a/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx b/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx index 2bd3a1bd8..45fb9de76 100644 --- a/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx +++ b/ts/components/dialog/debug/playgrounds/ProPlaygroundPage.tsx @@ -8,12 +8,12 @@ import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; import { DebugButton } from '../components'; import { DebugMenuPageProps, DebugMenuSection } from '../DebugMenuModal'; import { CTAVariant } from '../../cta/types'; -import { useIsProAvailable } from '../../../../hooks/useIsProAvailable'; +import { getIsProAvailableMemo } from '../../../../hooks/useIsProAvailable'; export function ProPlaygroundPage(props: DebugMenuPageProps) { const forceUpdate = useUpdate(); const handleClick = useShowSessionCTACbWithVariant(); - const proAvailable = useIsProAvailable(); + const proAvailable = getIsProAvailableMemo(); if (!proAvailable) { return null; diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 1ab2ec6a0..84708e73c 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -31,7 +31,7 @@ import { ModalPencilIcon } from '../../shared/ModalPencilButton'; import { ProfileHeader, ProfileName } from '../components'; import type { ProfileDialogModes } from '../ProfileDialogModes'; import { tr } from '../../../../localization/localeTools'; -import { useIsProAvailable } from '../../../../hooks/useIsProAvailable'; +import { getIsProAvailableMemo } from '../../../../hooks/useIsProAvailable'; import { setDebugMode } from '../../../../state/ducks/debug'; import { useHideRecoveryPasswordEnabled } from '../../../../state/selectors/settings'; import { OnionStatusLight } from '../../OnionStatusPathDialog'; @@ -100,7 +100,7 @@ function LucideIconForSettings(props: Omit` position: relative; width: 100%; @@ -81,7 +80,7 @@ const StyledBorder = styled(AnimatedFlex)<{ shape: 'round' | 'square' | 'none' } const StyledInput = styled(motion.input)<{ error: boolean; - textSize: TextSizes; + textSize: SessionInputTextSizes; centerText?: boolean; monospaced?: boolean; padding?: string; @@ -104,53 +103,10 @@ const StyledInput = styled(motion.input)<{ } `; -const StyledTextAreaContainer = styled(motion.div)<{ - error: boolean; - textSize: TextSizes; - centerText?: boolean; - monospaced?: boolean; - padding?: string; -}>` - display: flex; - align-items: center; - position: relative; - line-height: 1; - height: 100%; - width: 100%; - padding: ${props => (props.padding ? props.padding : 'var(--margins-md)')}; - - background: transparent; - color: ${props => (props.error ? 'var(--danger-color)' : 'var(--input-text-color)')}; - outline: 0; - - font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')}; - ${props => `font-size: var(--font-size-${props.textSize});`} - - textarea { - display: flex; - height: 100%; - width: 100%; - outline: 0; - border: none; - background: transparent; - - resize: none; - word-break: break-all; - user-select: all; - - &:placeholder-shown { - line-height: 1; - font-family: ${props => (props.monospaced ? 'var(--font-mono)' : 'var(--font-default)')}; - ${props => `font-size: var(--font-size-${props.textSize});`} - } - - &::placeholder { - color: var(--input-text-placeholder-color); - } - } -`; - -function BorderWithErrorState({ hasError, children }: { hasError: boolean } & PropsWithChildren) { +export function BorderWithErrorState({ + hasError, + children, +}: { hasError: boolean } & PropsWithChildren) { const inputShape = 'round'; return ( }; -type WithTextAreaRef = { inputRef?: RefObject }; - -function useUpdateInputValue(onValueChanged: (val: string) => void, disabled?: boolean) { - return useCallback( - (e: ChangeEvent) => { - if (disabled) { - return; - } - e.preventDefault(); - const val = e.target.value; - - onValueChanged(val); - }, - [disabled, onValueChanged] - ); -} type SimpleSessionInputProps = Pick< - Props, + GenericSessionInputProps, | 'type' | 'placeholder' | 'value' @@ -281,7 +221,7 @@ type SimpleSessionInputProps = Pick< | 'centerText' > & WithInputRef & - Required> & { + Required> & { onValueChanged: (str: string) => void; onEnterPressed: () => void; providedError: string | TrArgs | undefined; @@ -289,6 +229,11 @@ type SimpleSessionInputProps = Pick< buttonEnd?: ReactNode; }; +// NOTE: [react-compiler] this has to live here for the hook to be identified as static +function useUpdateInputValueInternal(...props: Parameters) { + return useUpdateInputValue(...props); +} + /** * A simpler version of the SessionInput component. * Does not handle CTA, textarea, nor monospaced fonts. @@ -323,7 +268,7 @@ export const SimpleSessionInput = (props: SimpleSessionInputProps) => { const hasError = !isEmpty(providedError); const hasValue = !isEmpty(value); - const updateInputValue = useUpdateInputValue(onValueChanged, disabled); + const updateInputValue = useUpdateInputValueInternal(onValueChanged, disabled); const paddingInlineEnd = usePaddingForButtonInlineEnd({ hasButtonInlineEnd: !!buttonEnd && hasValue, @@ -396,140 +341,6 @@ export const ModalSimpleSessionInput = (props: Omit; }; -/** - * - * Also, and just like SimpleSessionInput, error handling and value management is to be done by the parent component. - * Providing `error` will make the textarea red and the error string displayed below it. - * This component should only be used for TextArea that does not need remote validations, as the error - * state is live. For remote validations, use the SessionInput component. - */ -export const SimpleSessionTextarea = ( - props: Pick< - Props, - | 'placeholder' - | 'value' - | 'ariaLabel' - | 'maxLength' - | 'autoFocus' - | 'inputDataTestId' - | 'textSize' - | 'padding' - | 'required' - | 'tabIndex' - > & - WithTextAreaRef & - Required> & { - onValueChanged: (str: string) => void; - providedError: string | TrArgs | undefined; - disabled?: boolean; - buttonEnd?: ReactNode; - } & ({ singleLine: false } | { singleLine: true; onEnterPressed: () => void }) -) => { - const { - placeholder, - value, - ariaLabel, - maxLength, - providedError, - onValueChanged, - autoFocus, - inputRef, - inputDataTestId, - errorDataTestId, - textSize = 'sm', - disabled, - padding, - required, - tabIndex, - buttonEnd, - } = props; - const hasError = !isEmpty(providedError); - const hasValue = !isEmpty(value); - - const ref = useRef(inputRef?.current || null); - - const updateInputValue = useUpdateInputValue(onValueChanged, disabled); - - const paddingInlineEnd = usePaddingForButtonInlineEnd({ - hasButtonInlineEnd: !!buttonEnd && hasValue, - }); - - const inputProps: any = { - type: 'text', - placeholder, - value, - textSize, - disabled, - maxLength, - padding, - autoFocus, - 'data-testid': inputDataTestId, - required, - 'aria-required': required, - tabIndex, - onChange: updateInputValue, - style: { paddingInlineEnd, lineHeight: 1.5 }, - }; - - const containerProps = { - error: hasError, - textSize, - padding, - }; - - useEffect(() => { - const textarea = ref.current; - if (textarea) { - // don't ask me why, but we need to reset the height to auto before calculating it here - textarea.style.height = 'auto'; - // we want 12 lines of text at most - textarea.style.height = `${Math.min(textarea.scrollHeight, 12 * parseFloat(getComputedStyle(textarea).lineHeight))}px`; - } - }, [ref, value]); - - return ( - - - -