diff --git a/payment-iq/app/features/AdvancedSearch/store/advancedSearchSlice.ts b/payment-iq/app/features/AdvancedSearch/store/advancedSearchSlice.ts new file mode 100644 index 0000000..43b055c --- /dev/null +++ b/payment-iq/app/features/AdvancedSearch/store/advancedSearchSlice.ts @@ -0,0 +1,56 @@ +import { createSlice } from '@reduxjs/toolkit'; + +interface AdvancedSearchState { + keyword: string, + transactionID: string, + transactionReferenceId: string, + user: string, + currency: string, + state: string, + statusDescription: string, + transactionType: string, + paymentMethod: string, + psps: string, + initialPsps: string, + merchants: string, + startDate: null | string, + endDate: null | string, + lastUpdatedFrom: null | string, + lastUpdatedTo: null | string, + minAmount: string, + maxAmount: string, + channel: string, +} + +const initialState: AdvancedSearchState = { + keyword: "", + transactionID: "", + transactionReferenceId: "", + user: "", + currency: "", + state: "", + statusDescription: "", + transactionType: "", + paymentMethod: "", + psps: "", + initialPsps: "", + merchants: "", + startDate: null, + endDate: null, + lastUpdatedFrom: null, + lastUpdatedTo: null, + minAmount: "", + maxAmount: "", + channel: "", +}; + +const advancedSearchSlice = createSlice({ + name: 'advancedSearch', + initialState, + reducers: { + }, +}, +); + +export default advancedSearchSlice.reducer; + diff --git a/payment-iq/app/features/Pages/transactions/Transactions.tsx b/payment-iq/app/features/Pages/transactions/Transactions.tsx index 8bcb8aa..a8629c5 100644 --- a/payment-iq/app/features/Pages/transactions/Transactions.tsx +++ b/payment-iq/app/features/Pages/transactions/Transactions.tsx @@ -77,42 +77,41 @@ export default function TransactionTable() { channel: "", }); }; - - const filterRows = (rows1, filters) => { + + const filterRows = (rows1, filters) => { // debugger - return rows1.filter(row => { - const hasTransactionIdFilter = filters.transactionID !== ""; - const hasStateFilter = filters.state !== ""; + return rows1.filter(row => { + const hasTransactionIdFilter = filters.transactionID !== ""; + const hasStateFilter = filters.state !== ""; - console.log(1111, filters.transactionID, hasTransactionIdFilter) - if (hasTransactionIdFilter && hasStateFilter) { - console.log(1234) - // Return rows that match BOTH filters - return row.transactionID == filters.transactionID && row.state.toLowerCase() === filters.state.toLowerCase(); - } else if (hasTransactionIdFilter) { - console.log(12345) - // Return rows that match merchandId only - return row.transactionID == filters.transactionID; - } else if (hasStateFilter) { - // Return rows that match state only - console.log(123456) - return row.state.toLowerCase() === filters.state.toLowerCase(); - } else { + if (hasTransactionIdFilter && hasStateFilter) { + console.log(1234) + // Return rows that match BOTH filters + return row.transactionID == filters.transactionID && row.state.toLowerCase() === filters.state.toLowerCase(); + } else if (hasTransactionIdFilter) { + console.log(12345) + // Return rows that match merchandId only + return row.transactionID == filters.transactionID; + } else if (hasStateFilter) { + // Return rows that match state only + console.log(123456) + return row.state.toLowerCase() === filters.state.toLowerCase(); + } else { console.log(1234567) - // No filters applied, return all rows - return rows; - } - }); -}; + // No filters applied, return all rows + return rows; + } + }); + }; - useEffect(()=>{ + useEffect(() => { console.log(form) console.log(filterRows(rows, { transactionID: form.transactionID, state: form.state })) - setFilteredRows(filterRows(rows, { transactionID: form.transactionID, state: form.state })); - },[form]) + setFilteredRows(filterRows(rows, { transactionID: form.transactionID, state: form.state })); + }, [form]) // useEffect(()=>{ // if(form?.transactionId){ diff --git a/payment-iq/app/layout.tsx b/payment-iq/app/layout.tsx index 2a6d7a1..142102a 100644 --- a/payment-iq/app/layout.tsx +++ b/payment-iq/app/layout.tsx @@ -1,6 +1,8 @@ import ThemeRegistry from "@/config/ThemeRegistry"; import type { Metadata } from "next"; import "../styles/globals.scss"; +import { Providers } from "./providers/providers"; +import { MSWProvider } from './providers/msw-provider'; export const metadata: Metadata = { title: "Your App", @@ -15,7 +17,11 @@ export default function RootLayout({ return ( - {children} + + + {children} + + ); diff --git a/payment-iq/app/providers/msw-provider.tsx b/payment-iq/app/providers/msw-provider.tsx new file mode 100644 index 0000000..9f3bf55 --- /dev/null +++ b/payment-iq/app/providers/msw-provider.tsx @@ -0,0 +1,13 @@ +'use client'; +import { useEffect } from 'react'; + +export function MSWProvider({ children }: { children: React.ReactNode }) { + useEffect(() => { + if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { + const { worker } = require('../../mock/browser.ts'); + worker.start(); + } + }, []); + + return <>{children}; +} diff --git a/payment-iq/app/providers/providers.tsx b/payment-iq/app/providers/providers.tsx new file mode 100644 index 0000000..ff55a46 --- /dev/null +++ b/payment-iq/app/providers/providers.tsx @@ -0,0 +1,10 @@ +'use client'; + +import { ReactNode } from 'react'; +import { Provider } from 'react-redux'; +import { store } from '../../lib/store'; + +export function Providers({ children }: { children: ReactNode }) { + return {children}; +} + diff --git a/payment-iq/app/test/page.tsx b/payment-iq/app/test/page.tsx new file mode 100644 index 0000000..966a371 --- /dev/null +++ b/payment-iq/app/test/page.tsx @@ -0,0 +1,50 @@ +// app/test/page.tsx +'use client'; + +import { useEffect, useState } from 'react'; + +export default function TestPage() { + const [user, setUser] = useState(null); + const [loginStatus, setLoginStatus] = useState(''); + + useEffect(() => { + // Test GET request + fetch('https://api.example.com/user') + .then(res => res.json()) + .then(data => setUser(data)); + }, []); + + const handleLogin = async () => { + // Test POST request + const response = await fetch('https://api.example.com/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username: 'admin', + password: 'password123' + }) + }); + + const result = await response.json(); + setLoginStatus(response.ok ? 'Login successful' : `Error: ${result.error}`); + }; + + return ( +
+

MSW Test Page

+ +
+

User Data (GET)

+
{JSON.stringify(user, null, 2)}
+
+ +
+

Login Test (POST)

+ +

{loginStatus}

+
+
+ ); +} diff --git a/payment-iq/app/testWithParams/page.tsx b/payment-iq/app/testWithParams/page.tsx new file mode 100644 index 0000000..71f1def --- /dev/null +++ b/payment-iq/app/testWithParams/page.tsx @@ -0,0 +1,97 @@ +// app/products/page.tsx +'use client'; + +import { useState } from 'react'; + +export default function ProductsPage() { + const [category, setCategory] = useState(''); + const [sort, setSort] = useState('price'); + const [limit, setLimit] = useState('10'); + const [products, setProducts] = useState([]); + const [loading, setLoading] = useState(false); + + const fetchProducts = async () => { + setLoading(true); + try { + // Construct URL with query parameters + const url = new URL('https://api.example.com/products'); + if (category) url.searchParams.append('category', category); + if (sort) url.searchParams.append('sort', sort); + if (limit) url.searchParams.append('limit', limit); + + const response = await fetch(url.toString()); + const data = await response.json(); + setProducts(data.products); + } catch (error) { + console.error('Error fetching products:', error); + } finally { + setLoading(false); + } + }; + + return ( +
+

Product Search

+ +
+
+ + setCategory(e.target.value)} + className="border p-2 rounded" + placeholder="electronics, clothing, etc." + /> +
+ +
+ + +
+ +
+ + setLimit(e.target.value)} + className="border p-2 rounded" + min="1" + max="100" + /> +
+ + +
+ + {products.length > 0 && ( +
+

Results

+
+ {products.map((product) => ( +
+

{product.name}

+

Category: {product.category}

+

Price: ${product.price}

+
+ ))} +
+
+ )} +
+ ); +} diff --git a/payment-iq/lib/store.ts b/payment-iq/lib/store.ts new file mode 100644 index 0000000..812f9b7 --- /dev/null +++ b/payment-iq/lib/store.ts @@ -0,0 +1,12 @@ +import { configureStore } from '@reduxjs/toolkit'; +import advancedSearchReducer from '@/app/features/AdvancedSearch/store/advancedSearchSlice'; + +export const store = configureStore({ + reducer: { + advancedSearch: advancedSearchReducer, + }, +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + diff --git a/payment-iq/mock/browser.ts b/payment-iq/mock/browser.ts index 975f2cd..2845183 100644 --- a/payment-iq/mock/browser.ts +++ b/payment-iq/mock/browser.ts @@ -1,5 +1,9 @@ -// mocks/browser.ts -import { setupWorker } from "msw/browser"; -import { handlers } from "./handlers"; +// // mocks/browser.ts import { setupWorker } from "msw/browser"; +// import { handlers } from "./handlers"; +// +// export const worker = setupWorker(...handlers); + +import { setupWorker } from 'msw/browser'; +import { handlers } from './handlers'; export const worker = setupWorker(...handlers); diff --git a/payment-iq/mock/handlers.ts b/payment-iq/mock/handlers.ts index 6db727a..902d618 100644 --- a/payment-iq/mock/handlers.ts +++ b/payment-iq/mock/handlers.ts @@ -1,96 +1,98 @@ -import { http, HttpResponse } from "msw"; +// import { http, HttpResponse } from "msw"; +// +// export const handlers = [ +// http.get( +// "https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/metrics/txsummary", +// (req, _res, _ctx) => { +// const merchantId = req.url.searchParams.get("merchantId"); +// const fromDate = req.url.searchParams.get("fromDate"); +// const toDate = req.url.searchParams.get("toDate"); +// +// console.log(merchantId, fromDate, toDate); +// +// return HttpResponse.json({ +// result: { +// txCount: { total: 0, successful: 0 }, +// amount: { value: "0", currency: "EUR" }, +// }, +// }); +// } +// ), +// ]; + + +import { http, HttpResponse } from 'msw'; export const handlers = [ - http.get( - "https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/metrics/txsummary", - (req, _res, _ctx) => { - const merchantId = req.url.searchParams.get("merchantId"); - const fromDate = req.url.searchParams.get("fromDate"); - const toDate = req.url.searchParams.get("toDate"); + // Simple GET endpoint + http.get('https://api.example.com/user', () => { + return HttpResponse.json({ + id: 'usr_123', + name: 'John Doe', + email: 'john@example.com' + }); + }), - console.log(merchantId, fromDate, toDate); + // POST endpoint with request validation + http.post('https://api.example.com/login', async ({ request }) => { + const { username, password } = await request.json() as { username: string; password: string }; + if (username === 'admin' && password === 'password123') { return HttpResponse.json({ - result: { - txCount: { total: 0, successful: 0 }, - amount: { value: "0", currency: "EUR" }, - }, + token: 'mock-jwt-token', + user: { id: 'usr_123', name: 'Admin User' } }); } - ), - http.get( - "https://test-bo.paymentiq.io/paymentiq/backoffice/api/v2/users/", - (req, _res, _ctx) => { - // Mock data for merchantId = 100987998 - if (true) { - return HttpResponse.json({ - result: [ - { - merchantId: 100987998, - id: "bc6a8a55-13bc-4538-8255-cd0cec3bb4e9", - username: "lspaddy", - firstName: "Paddy", - lastName: "Man", - email: "patrick@omegasys.eu", - phone: "", - jobTitle: "", - enabled: true, - authorities: [ - "ROLE_IIN", - "ROLE_FIRST_APPROVER", - "ROLE_RULES_ADMIN", - "ROLE_TRANSACTION_VIEWER", - "ROLE_IIN_ADMIN", - "ROLE_USER_PSP_ACCOUNT", - ], - allowedMerchantIds: [100987998], - created: "2025-05-04T15:32:48.432Z", - disabledBy: null, - disabledDate: null, - disabledReason: null, - incidentNotes: false, - lastLogin: "", - lastMandatoryUpdated: "2025-05-04T15:32:48.332Z", - marketingNewsletter: false, - releaseNotes: false, - requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"], - twoFactorCondition: "required", - twoFactorCredentials: [], - }, - { - merchantId: 100987998, - id: "382eed15-1e21-41fa-b1f3-0c1adb3af714", - username: "lsterence", - firstName: "Terence", - lastName: "User", - email: "terence@omegasys.eu", - phone: "", - jobTitle: "", - enabled: true, - authorities: [ - "ROLE_IIN", - "ROLE_FIRST_APPROVER", - "ROLE_RULES_ADMIN", - ], - allowedMerchantIds: [100987998], - created: "2025-05-04T15:32:48.432Z", - disabledBy: null, - disabledDate: null, - disabledReason: null, - incidentNotes: false, - lastLogin: "", - lastMandatoryUpdated: "2025-05-04T15:32:48.332Z", - marketingNewsletter: false, - releaseNotes: false, - requiredActions: ["CONFIGURE_TOTP", "UPDATE_PASSWORD"], - twoFactorCondition: "required", - twoFactorCredentials: [], - }, - // Add more users if needed - ], - total: 4, - }); - } + + return HttpResponse.json( + { error: 'Invalid credentials' }, + { status: 401 } + ); + }), + + + // Example with query parameters + http.get('https://api.example.com/products', ({ request }) => { + // Parse the URL to access query parameters + const url = new URL(request.url); + + // Get query parameters + const category = url.searchParams.get('category'); + const sort = url.searchParams.get('sort') || 'price'; + const page = url.searchParams.get('page') || '1'; + const limit = url.searchParams.get('limit') || '10'; + + // Validate parameters + if (limit && parseInt(limit) > 100) { + return HttpResponse.json( + { error: 'Limit cannot exceed 100' }, + { status: 400 } + ); } - ), + + // Generate mock response based on parameters + const mockProducts = Array.from({ length: parseInt(limit) }, (_, i) => ({ + id: i + 1, + name: `Product ${i + 1}${category ? ` in ${category}` : ''}`, + price: Math.floor(Math.random() * 100), + category: category || 'general', + })); + + console.log(1234, mockProducts) + + // Sort products if sort parameter provided + if (sort === 'price') { + mockProducts.sort((a, b) => a.price - b.price); + } else if (sort === 'name') { + mockProducts.sort((a, b) => a.name.localeCompare(b.name)); + } + + return HttpResponse.json({ + products: mockProducts, + page: parseInt(page), + totalPages: 5, + itemsPerPage: parseInt(limit), + sortBy: sort, + }); + }), ]; diff --git a/payment-iq/mock/server.ts b/payment-iq/mock/server.ts new file mode 100644 index 0000000..719bd8c --- /dev/null +++ b/payment-iq/mock/server.ts @@ -0,0 +1,5 @@ +// mocks/server.ts +import { setupServer } from 'msw/node'; +import { handlers } from './handlers'; + +export const server = setupServer(...handlers); diff --git a/payment-iq/next.config.ts b/payment-iq/next.config.ts index e9ffa30..b9172f5 100644 --- a/payment-iq/next.config.ts +++ b/payment-iq/next.config.ts @@ -2,6 +2,12 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ + webpack: (config) => { + if (process.env.NEXT_PUBLIC_API_MOCKING === 'enabled') { + config.resolve.alias['@mswjs/interceptors'] = false; + } + return config; + }, }; export default nextConfig; diff --git a/payment-iq/package.json b/payment-iq/package.json index d3f094a..c37bf54 100644 --- a/payment-iq/package.json +++ b/payment-iq/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { + "msw-init": "msw init public/ --save", "dev": "next dev --turbopack", "build": "next build", "start": "next start", @@ -15,6 +16,7 @@ "@mui/material": "^7.1.2", "@mui/x-data-grid": "^8.5.2", "@mui/x-date-pickers": "^8.5.3", + "@reduxjs/toolkit": "^2.8.2", "clsx": "^2.1.1", "date-fns": "^4.1.0", "dayjs": "^1.11.13", @@ -23,6 +25,7 @@ "react": "^19.0.0", "react-date-range": "^2.0.1", "react-dom": "^19.0.0", + "react-redux": "^9.2.0", "recharts": "^2.15.3", "sass": "^1.89.2", "xlsx": "^0.18.5" @@ -34,6 +37,7 @@ "@types/react": "^19", "@types/react-date-range": "^1.4.10", "@types/react-dom": "^19", + "@types/react-redux": "^7.1.34", "eslint": "^9", "eslint-config-next": "15.3.3", "msw": "^2.10.2", @@ -44,4 +48,4 @@ "public" ] } -} \ No newline at end of file +} diff --git a/payment-iq/yarn.lock b/payment-iq/yarn.lock index cc739b9..2400af5 100644 --- a/payment-iq/yarn.lock +++ b/payment-iq/yarn.lock @@ -47,7 +47,7 @@ dependencies: "@babel/types" "^7.27.3" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.27.1", "@babel/runtime@^7.27.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.27.1", "@babel/runtime@^7.27.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.27.6" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz" integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== @@ -850,6 +850,18 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== +"@reduxjs/toolkit@^2.8.2": + version "2.8.2" + resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.8.2.tgz#f4e9f973c6fc930c1e0f3bf462cc95210c28f5f9" + integrity sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A== + dependencies: + "@standard-schema/spec" "^1.0.0" + "@standard-schema/utils" "^0.3.0" + immer "^10.0.3" + redux "^5.0.1" + redux-thunk "^3.1.0" + reselect "^5.1.0" + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz" @@ -860,6 +872,16 @@ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz" integrity sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ== +"@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== + "@swc/counter@0.1.3": version "0.1.3" resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" @@ -945,6 +967,14 @@ resolved "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz" integrity sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A== +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.6" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz#6bba74383cdab98e8db4e20ce5b4a6b98caed010" + integrity sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" @@ -985,6 +1015,16 @@ resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz" integrity sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw== +"@types/react-redux@^7.1.34": + version "7.1.34" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.34.tgz#83613e1957c481521e6776beeac4fd506d11bd0e" + integrity sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-transition-group@^4.4.12": version "4.4.12" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz" @@ -1007,6 +1047,11 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== +"@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== + "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": version "8.34.1" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz" @@ -2420,7 +2465,7 @@ headers-polyfill@^4.0.2: resolved "https://registry.yarnpkg.com/headers-polyfill/-/headers-polyfill-4.0.3.tgz#922a0155de30ecc1f785bcf04be77844ca95ad07" integrity sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ== -hoist-non-react-statics@^3.3.1: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -2437,6 +2482,11 @@ ignore@^7.0.0: resolved "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz" integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== +immer@^10.0.3: + version "10.1.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc" + integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw== + immutable@^5.0.2: version "5.1.3" resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.3.tgz#e6486694c8b76c37c063cca92399fa64098634d4" @@ -3174,6 +3224,14 @@ react-list@^0.8.13: resolved "https://registry.npmjs.org/react-list/-/react-list-0.8.18.tgz" integrity sha512-1OSdDvzuKuwDJvQNuhXxxL+jTmmdtKg1i6KtYgxI9XR98kbOql1FcSGP+Lcvo91fk3cYng+Z6YkC6X9HRJwxfw== +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== + dependencies: + "@types/use-sync-external-store" "^0.0.6" + use-sync-external-store "^1.4.0" + react-smooth@^4.0.4: version "4.0.4" resolved "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz" @@ -3224,6 +3282,23 @@ recharts@^2.15.3: tiny-invariant "^1.3.1" victory-vendor "^36.6.8" +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.0.0: + 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" resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz" @@ -3260,7 +3335,7 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== -reselect@^5.1.1: +reselect@^5.1.0, reselect@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz" integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w== @@ -3832,7 +3907,7 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -use-sync-external-store@^1.5.0: +use-sync-external-store@^1.4.0, use-sync-external-store@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz" integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==