Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
93f469f786 | |||
c486780fea | |||
3b22f1b3b8 | |||
2dfd830106 | |||
ddc1467089 | |||
0948e41294 | |||
7c12c70f90 | |||
b989b55426 | |||
de5ef7e925 | |||
401d8f1389 | |||
b228932444 | |||
0e352f36ee | |||
0e225e9f18 | |||
1131ef915f | |||
b6646ed54f | |||
3a84c260d0 | |||
035fd231c9 | |||
2fba38b604 | |||
7ea3524524 | |||
15fc3b1ae9 | |||
1799263212 |
@ -1 +1 @@
|
|||||||
REACT_APP_DOMAIN="https://hub.pena.digital"
|
REACT_APP_DOMAIN=""
|
||||||
|
26
.gitea/workflows/deployProd.yml
Normal file
26
.gitea/workflows/deployProd.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Deploy
|
||||||
|
run-name: ${{ gitea.actor }} build image and push to container registry
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CreateImage:
|
||||||
|
runs-on: [skeris]
|
||||||
|
uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/build-image.yml@v1.1.6-p
|
||||||
|
with:
|
||||||
|
runner: skeris
|
||||||
|
secrets:
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
DeployService:
|
||||||
|
runs-on: [frontprod]
|
||||||
|
#needs: CreateImage
|
||||||
|
uses: https://gitea.pena/PenaDevops/actions.git/.gitea/workflows/deploy.yml@v1.1.4-p7
|
||||||
|
with:
|
||||||
|
runner: hubprod
|
||||||
|
actionid: ${{ gitea.run_id }}
|
||||||
|
|
||||||
|
|
26
.gitea/workflows/deployStaging.yml
Normal file
26
.gitea/workflows/deployStaging.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Deploy
|
||||||
|
run-name: ${{ gitea.actor }} build image and push to container registry
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'staging'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
CreateImage:
|
||||||
|
runs-on: [hubstaging]
|
||||||
|
uses: http://gitea.pena/PenaDevops/actions.git/.gitea/workflows/build-image.yml@v1.1.6-p
|
||||||
|
with:
|
||||||
|
runner: hubstaging
|
||||||
|
secrets:
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
||||||
|
DeployService:
|
||||||
|
runs-on: [frontstaging]
|
||||||
|
needs: CreateImage
|
||||||
|
uses: http://gitea.pena/PenaDevops/actions.git/.gitea/workflows/deploy.yml@v1.1.4-p7
|
||||||
|
with:
|
||||||
|
runner: frontstaging
|
||||||
|
actionid: ${{ gitea.run_id }}
|
||||||
|
|
||||||
|
|
14
.gitea/workflows/lint.yml
Normal file
14
.gitea/workflows/lint.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: Lint
|
||||||
|
run-name: ${{ gitea.actor }} produce linting
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'dev'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Lint:
|
||||||
|
runs-on: [hubstaging]
|
||||||
|
uses: http://gitea.pena/PenaDevops/actions.git/.gitea/workflows/lint.yml@v1.1.0
|
||||||
|
with:
|
||||||
|
runner: hubstaging
|
1
.npmrc
Normal file
1
.npmrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
@frontend:registry=http://gitea.pena/api/packages/skeris/npm/
|
15
Containerfile
Normal file
15
Containerfile
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
FROM gitea.pena/penadevops/container-images/node:main as build
|
||||||
|
|
||||||
|
RUN apk update && rm -rf /var/cache/apk/*
|
||||||
|
WORKDIR /usr/app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm install --force && yarn cache clean
|
||||||
|
RUN psstat.sh "npm run build"
|
||||||
|
|
||||||
|
|
||||||
|
FROM gitea.pena/penadevops/container-images/nginx:main as result
|
||||||
|
WORKDIR /usr/share/nginx/html
|
||||||
|
COPY --from=build /usr/app/build/ /usr/share/nginx/html
|
||||||
|
COPY fallback.js /usr/share/nginx/html/fallback.js
|
||||||
|
COPY hub.conf /etc/nginx/conf.d/default.conf
|
15
Dockerfile
15
Dockerfile
@ -1,15 +0,0 @@
|
|||||||
FROM penahub.gitlab.yandexcloud.net:5050/devops/dockerhub-backup/node as build
|
|
||||||
|
|
||||||
RUN apk update && rm -rf /var/cache/apk/*
|
|
||||||
WORKDIR /usr/app
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN yarn install --ignore-scripts --non-interactive --frozen-lockfile && yarn cache clean
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
|
|
||||||
FROM penahub.gitlab.yandexcloud.net:5050/devops/dockerhub-backup/nginx as result
|
|
||||||
WORKDIR /usr/share/nginx/html
|
|
||||||
COPY --from=build /usr/app/build/ /usr/share/nginx/html
|
|
||||||
COPY fallback.js /usr/share/nginx/html/fallback.js
|
|
||||||
COPY hub.conf /etc/nginx/conf.d/default.conf
|
|
@ -1,9 +1,8 @@
|
|||||||
version: "3"
|
|
||||||
services:
|
services:
|
||||||
hub:
|
hub:
|
||||||
container_name: hub
|
container_name: hub
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
image: $CI_REGISTRY_IMAGE/main:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
|
||||||
hostname: hub
|
hostname: hub
|
||||||
|
image: gitea.pena/penaside/front-hub/main:1118
|
||||||
tty: true
|
tty: true
|
||||||
|
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
version: "3"
|
|
||||||
services:
|
services:
|
||||||
hub:
|
hub:
|
||||||
container_name: hub
|
container_name: hub
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
image: $CI_REGISTRY_IMAGE/staging:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
image: gitea.pena/penaside/front-hub/staging:$GITHUB_RUN_NUMBER
|
||||||
networks:
|
|
||||||
- marketplace_penahub_frontend
|
|
||||||
hostname: hub
|
hostname: hub
|
||||||
tty: true
|
tty: true
|
||||||
networks:
|
|
||||||
marketplace_penahub_frontend:
|
|
||||||
external: true
|
|
||||||
|
|
||||||
|
26099
package-lock.json
generated
Normal file
26099
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -3,7 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "craco start",
|
"start": "NODE_OPTIONS=\"--max-old-space-size=1024\" craco start",
|
||||||
"build": "craco build",
|
"build": "craco build",
|
||||||
"test": "craco test --env=node --transformIgnorePatterns \"node_modules/(?!@frontend)/\"",
|
"test": "craco test --env=node --transformIgnorePatterns \"node_modules/(?!@frontend)/\"",
|
||||||
"test:cart": "vitest ./src/utils/calcCart",
|
"test:cart": "vitest ./src/utils/calcCart",
|
||||||
@ -16,7 +16,7 @@
|
|||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
"@frontend/kitui": "^1.0.82",
|
"@frontend/kitui": "^1.0.108",
|
||||||
"@mui/icons-material": "^5.10.14",
|
"@mui/icons-material": "^5.10.14",
|
||||||
"@mui/material": "^5.10.14",
|
"@mui/material": "^5.10.14",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
@ -36,7 +36,7 @@
|
|||||||
"react-error-boundary": "^4.0.11",
|
"react-error-boundary": "^4.0.11",
|
||||||
"react-pdf": "^7.1.2",
|
"react-pdf": "^7.1.2",
|
||||||
"react-router-dom": "^6.23.0",
|
"react-router-dom": "^6.23.0",
|
||||||
"react-slick": "^0.29.0",
|
"react-slick": "^0.30.3",
|
||||||
"slick-carousel": "^1.8.1",
|
"slick-carousel": "^1.8.1",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
@ -53,7 +53,7 @@
|
|||||||
"@types/node": "^16.7.13",
|
"@types/node": "^16.7.13",
|
||||||
"@types/react": "^18.0.0",
|
"@types/react": "^18.0.0",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.0",
|
||||||
"@types/react-slick": "^0.23.10",
|
"@types/react-slick": "^0.23.13",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||||
"@typescript-eslint/parser": "^6.9.1",
|
"@typescript-eslint/parser": "^6.9.1",
|
||||||
"craco-alias": "^3.0.1",
|
"craco-alias": "^3.0.1",
|
||||||
@ -75,5 +75,6 @@
|
|||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ export const getTariffs = async (
|
|||||||
try {
|
try {
|
||||||
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
|
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${API_URL}/tariff?page=${apiPage}&limit=${tariffsPerPage}`,
|
url: `${API_URL}/tariff/getList?page=${apiPage}&limit=${tariffsPerPage}`,
|
||||||
useToken: true,
|
useToken: true,
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
|
@ -77,12 +77,14 @@ export const sendFile = async (
|
|||||||
|
|
||||||
export const createTicket = async (
|
export const createTicket = async (
|
||||||
ticketNameField: string,
|
ticketNameField: string,
|
||||||
ticketBodyField: string
|
ticketBodyField: string,
|
||||||
|
isToken?: boolean
|
||||||
): Promise<[CreateTicketResponse | null, string?]> => {
|
): Promise<[CreateTicketResponse | null, string?]> => {
|
||||||
try {
|
try {
|
||||||
const createTicketResponse = await createTicketRequest({
|
const createTicketResponse = await createTicketRequest({
|
||||||
url: `${API_URL}/create`,
|
url: `${API_URL}/create`,
|
||||||
body: { Title: ticketNameField, Message: ticketBodyField },
|
body: { Title: ticketNameField, Message: ticketBodyField, System: false },
|
||||||
|
useToken: isToken
|
||||||
});
|
});
|
||||||
|
|
||||||
return [createTicketResponse];
|
return [createTicketResponse];
|
||||||
|
@ -16,15 +16,29 @@ interface PaymentBody {
|
|||||||
|
|
||||||
export const sendPayment = async ({
|
export const sendPayment = async ({
|
||||||
userId,
|
userId,
|
||||||
|
wayback,
|
||||||
body,
|
body,
|
||||||
fromSquiz,
|
fromSquiz,
|
||||||
paymentPurpose,
|
paymentPurpose,
|
||||||
}: {
|
}: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
wayback: string;
|
||||||
body: PaymentBody;
|
body: PaymentBody;
|
||||||
fromSquiz: boolean;
|
fromSquiz: boolean;
|
||||||
paymentPurpose: "paycart" | "replenishwallet";
|
paymentPurpose: "paycart" | "replenishwallet";
|
||||||
}): Promise<[SendPaymentResponse | null, string?]> => {
|
}): Promise<[SendPaymentResponse | null, string?]> => {
|
||||||
|
|
||||||
|
console.log(" я sendPayment и вот мой wayback = " + wayback)
|
||||||
|
|
||||||
|
let returnUrl= `https://${isStaging}hub.pena.digital/afterpay?from=${
|
||||||
|
fromSquiz ? "quiz" : "hub"
|
||||||
|
}&purpose=${paymentPurpose}&userid=${userId}`
|
||||||
|
|
||||||
|
if (wayback) returnUrl += `&wayback=${wayback}`
|
||||||
|
|
||||||
|
console.log("returnUrl")
|
||||||
|
console.log(returnUrl)
|
||||||
|
|
||||||
const reqeustBody = {
|
const reqeustBody = {
|
||||||
currency: "RUB",
|
currency: "RUB",
|
||||||
bankCard: {
|
bankCard: {
|
||||||
@ -36,9 +50,7 @@ export const sendPayment = async ({
|
|||||||
},
|
},
|
||||||
phoneNumber: "79000000000",
|
phoneNumber: "79000000000",
|
||||||
login: "login_test",
|
login: "login_test",
|
||||||
returnUrl: `https://${isStaging}hub.pena.digital/afterpay?from=${
|
returnUrl,
|
||||||
fromSquiz ? "quiz" : "hub"
|
|
||||||
}&purpose=${paymentPurpose}&userid=${userId}`,
|
|
||||||
...body,
|
...body,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import {
|
||||||
|
getAuthToken,
|
||||||
getMessageFromFetchError,
|
getMessageFromFetchError,
|
||||||
throttle,
|
throttle,
|
||||||
TicketMessage,
|
TicketMessage,
|
||||||
@ -150,12 +151,19 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
}, []),
|
}, []),
|
||||||
onFetchStateChange: setUnauthTicketMessageFetchState,
|
onFetchStateChange: setUnauthTicketMessageFetchState,
|
||||||
});
|
});
|
||||||
|
console.log("sessionData")
|
||||||
|
console.log(sessionData)
|
||||||
useSSESubscription<TicketMessage>({
|
useSSESubscription<TicketMessage>({
|
||||||
enabled: sseEnabled && isActiveSSETab && Boolean(sessionData),
|
enabled: sseEnabled && isActiveSSETab && Boolean(sessionData),
|
||||||
url:
|
url:
|
||||||
process.env.REACT_APP_DOMAIN +
|
process.env.REACT_APP_DOMAIN +
|
||||||
`/heruvym/v1.0.0/ticket?ticket=${sessionData?.ticketId}&s=${sessionData?.sessionId}`,
|
`/heruvym/v1.0.0/ticket?ticket=${sessionData?.ticketId}&s=${sessionData?.sessionId}`,
|
||||||
|
|
||||||
onNewData: (ticketMessages) => {
|
onNewData: (ticketMessages) => {
|
||||||
|
console.log("Chat")
|
||||||
|
|
||||||
|
console.log("ticketMessages useSSESubscription ")
|
||||||
|
console.log(ticketMessages)
|
||||||
const isTicketClosed = ticketMessages.some(
|
const isTicketClosed = ticketMessages.some(
|
||||||
(message) => message.session_id === "close"
|
(message) => message.session_id === "close"
|
||||||
);
|
);
|
||||||
@ -167,10 +175,14 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("under checking some close message -----------------------------------------")
|
||||||
|
|
||||||
updateSSEValue(ticketMessages);
|
updateSSEValue(ticketMessages);
|
||||||
addOrUpdateUnauthMessages(ticketMessages);
|
addOrUpdateUnauthMessages(ticketMessages);
|
||||||
},
|
},
|
||||||
onDisconnect: useCallback(() => {
|
onDisconnect: useCallback(() => {
|
||||||
|
console.log("DISCONNECT")
|
||||||
setUnauthIsPreventAutoscroll(false);
|
setUnauthIsPreventAutoscroll(false);
|
||||||
setSseEnabled(false);
|
setSseEnabled(false);
|
||||||
}, []),
|
}, []),
|
||||||
@ -202,7 +214,7 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
const message = getMessageFromFetchError(error);
|
const message = getMessageFromFetchError(error);
|
||||||
if (message) enqueueSnackbar(message);
|
if (message) enqueueSnackbar(message);
|
||||||
},
|
},
|
||||||
onFetchStateChange: () => {},
|
onFetchStateChange: () => { },
|
||||||
enabled: Boolean(user),
|
enabled: Boolean(user),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -245,12 +257,40 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open && messages.length > 1) {
|
||||||
const newMessages = messages.filter(({ shown }) => shown.me !== 1);
|
let lastUnreadMessage = null;
|
||||||
|
|
||||||
|
// Ищем последнее непрочитанное чужое сообщение до первого прочитанного или своего
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const message = messages[i];
|
||||||
|
const isOwnMessage = (ticket.sessionData?.sessionId || user) === message.user_id;
|
||||||
|
|
||||||
|
// Пропускаем системные сообщения
|
||||||
|
if (message.ticket_id === "111") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если встретили своё сообщение - прерываем поиск
|
||||||
|
if (isOwnMessage) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если встретили прочитанное сообщение - прерываем поиск
|
||||||
|
if (message.shown?.me === 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если сообщение чужое и не прочитано - запоминаем его
|
||||||
|
if (!isOwnMessage && message.shown?.me !== 1) {
|
||||||
|
lastUnreadMessage = message;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newMessages.map(async ({ id }) => {
|
// Если нашли непрочитанное сообщение - отмечаем его как прочитанное
|
||||||
await shownMessage(id);
|
if (lastUnreadMessage) {
|
||||||
});
|
shownMessage(lastUnreadMessage.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [open, messages]);
|
}, [open, messages]);
|
||||||
|
|
||||||
@ -270,7 +310,9 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
|
|
||||||
const [createTicketresult, createTicketerror] = await createTicket(
|
const [createTicketresult, createTicketerror] = await createTicket(
|
||||||
"Unauth title",
|
"Unauth title",
|
||||||
messageField
|
messageField,
|
||||||
|
//При создании тикета, если нет у клиента токена, то хедер authorization вовсе не нужно слать
|
||||||
|
Boolean(getAuthToken())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (createTicketerror) {
|
if (createTicketerror) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect, forwardRef } from "react";
|
import { useState, useEffect, forwardRef, useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Fab,
|
Fab,
|
||||||
@ -71,6 +71,28 @@ export default function FloatingSupportChat() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unreadMessagesCount = useMemo(() => {
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
// Идём с конца массива к началу
|
||||||
|
for (let i = messages.length - 1; i >= 0; i--) {
|
||||||
|
const message = messages[i];
|
||||||
|
|
||||||
|
// Пропускаем сообщение с id "111"
|
||||||
|
if (message.id === "111") continue;
|
||||||
|
|
||||||
|
// Если сообщение не прочитано (shown.me !== 1)
|
||||||
|
if (message.shown.me !== 1) {
|
||||||
|
count++;
|
||||||
|
} else {
|
||||||
|
// Встретили прочитанное сообщение - прекращаем подсчёт
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}, [messages]); // Зависимость от messages - пересчитывается при их изменении
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onResize = () => {
|
const onResize = () => {
|
||||||
if (document.fullscreenElement) {
|
if (document.fullscreenElement) {
|
||||||
@ -153,7 +175,7 @@ export default function FloatingSupportChat() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Badge
|
<Badge
|
||||||
badgeContent={messages.filter(({ shown }) => shown.me !== 1).length}
|
badgeContent={unreadMessagesCount}
|
||||||
sx={{
|
sx={{
|
||||||
"& .MuiBadge-badge": {
|
"& .MuiBadge-badge": {
|
||||||
display: isChatOpened ? "none" : "flex",
|
display: isChatOpened ? "none" : "flex",
|
||||||
|
@ -40,6 +40,7 @@ export default function ProtectedLayout() {
|
|||||||
process.env.REACT_APP_DOMAIN +
|
process.env.REACT_APP_DOMAIN +
|
||||||
`/heruvym/v1.0.0/subscribe?Authorization=${token}`,
|
`/heruvym/v1.0.0/subscribe?Authorization=${token}`,
|
||||||
onNewData: (data) => {
|
onNewData: (data) => {
|
||||||
|
console.log("ProtectedLayout")
|
||||||
updateSSEValue(data);
|
updateSSEValue(data);
|
||||||
updateTickets(data.filter((d) => Boolean(d.id)));
|
updateTickets(data.filter((d) => Boolean(d.id)));
|
||||||
setTicketCount(data.length);
|
setTicketCount(data.length);
|
||||||
@ -63,6 +64,7 @@ export default function ProtectedLayout() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useAllTariffsFetcher({
|
useAllTariffsFetcher({
|
||||||
|
baseUrl: process.env.REACT_APP_DOMAIN + "/strator/tariff/getList",
|
||||||
onSuccess: updateTariffs,
|
onSuccess: updateTariffs,
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
const errorMessage = getMessageFromFetchError(error);
|
const errorMessage = getMessageFromFetchError(error);
|
||||||
|
@ -63,10 +63,8 @@ export default function DocumentItem({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof documentUrl === 'string') {
|
if (typeof documentUrl === 'string') {
|
||||||
if (!documentUrl.includes("pena.digital")) {
|
if (!documentUrl.includes("pena.digital")) {
|
||||||
console.log(documentUrl)
|
|
||||||
fetch(documentUrl)
|
fetch(documentUrl)
|
||||||
.then(e => {
|
.then(e => {
|
||||||
console.log(e)
|
|
||||||
setReadyShowDocument(true)
|
setReadyShowDocument(true)
|
||||||
})
|
})
|
||||||
.catch(e => console.log(e))
|
.catch(e => console.log(e))
|
||||||
|
@ -43,10 +43,8 @@ export default function DocumentUploadItem({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof urlOrFile === 'string') {
|
if (typeof urlOrFile === 'string') {
|
||||||
if (!urlOrFile.includes("pena.digital")) {
|
if (!urlOrFile.includes("pena.digital")) {
|
||||||
console.log(documentUrl)
|
|
||||||
fetch(documentUrl)
|
fetch(documentUrl)
|
||||||
.then(e => {
|
.then(e => {
|
||||||
console.log(e)
|
|
||||||
setReadyShowDocument(true)
|
setReadyShowDocument(true)
|
||||||
})
|
})
|
||||||
.catch(e => console.log(e))
|
.catch(e => console.log(e))
|
||||||
|
@ -20,6 +20,7 @@ export default () => {
|
|||||||
const userId = useUserStore((state) => state.user?._id);
|
const userId = useUserStore((state) => state.user?._id);
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const paymentUserId = searchParams.get("userid");
|
const paymentUserId = searchParams.get("userid");
|
||||||
|
const wayback = searchParams.get("wayback");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const from = searchParams.get("from") || "hub";
|
const from = searchParams.get("from") || "hub";
|
||||||
@ -70,9 +71,10 @@ export default () => {
|
|||||||
const domain = (host.includes("s") ? "s" : "") + from;
|
const domain = (host.includes("s") ? "s" : "") + from;
|
||||||
const pathname = from === "hub" ? "/tariffs" : "/list";
|
const pathname = from === "hub" ? "/tariffs" : "/list";
|
||||||
|
|
||||||
setRedirectUrl(
|
let redirect = `https://${domain}.pena.digital${pathname}?afterpay=${true}&userid=${userId}`
|
||||||
`https://${domain}.pena.digital${pathname}?afterpay=${true}&userid=${userId}`
|
if (wayback) redirect += `&wayback=${wayback}`
|
||||||
);
|
|
||||||
|
setRedirectUrl(redirect);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -133,3 +135,5 @@ export default () => {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//https://shub.pena.digital/quizpayment?action=squizpay&dif=50000&data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NDZlODc4hLWF1d__aACP1IpA&userid=6846e878c149e4d24ebf50f3&from=AI&wayback=ai_27964
|
@ -65,16 +65,18 @@ export default function Payment() {
|
|||||||
const [sorryModalOpen, setSorryModalOpen] = useState<boolean>(false);
|
const [sorryModalOpen, setSorryModalOpen] = useState<boolean>(false);
|
||||||
const [paymentValueField, setPaymentValueField] = useState<string>("0");
|
const [paymentValueField, setPaymentValueField] = useState<string>("0");
|
||||||
const [paymentLink, setPaymentLink] = useState<string>("");
|
const [paymentLink, setPaymentLink] = useState<string>("");
|
||||||
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
console.log("location", location);
|
|
||||||
console.log("location", location.state);
|
|
||||||
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
||||||
const userId = useUserStore((state) => state.userId);
|
const userId = useUserStore((state) => state.userId);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const handleCustomBackNavigation = useHistoryTracker();
|
const handleCustomBackNavigation = useHistoryTracker();
|
||||||
|
|
||||||
const {diffMoney, setNewDiff} = useDiffMoney()
|
|
||||||
|
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
|
||||||
|
const [waybackToSomeSite, setWaybackToSomeSite] = useState<string>("");
|
||||||
|
|
||||||
|
|
||||||
|
const { diffMoney, setNewDiff } = useDiffMoney()
|
||||||
|
|
||||||
const notEnoughMoneyAmount =
|
const notEnoughMoneyAmount =
|
||||||
(location.state?.notEnoughMoneyAmount as number) ?? 0;
|
(location.state?.notEnoughMoneyAmount as number) ?? 0;
|
||||||
@ -83,13 +85,12 @@ export default function Payment() {
|
|||||||
bigDecimal.multiply(parseFloat(paymentValueField), 100)
|
bigDecimal.multiply(parseFloat(paymentValueField), 100)
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(diffMoney)
|
if (diffMoney > 0) {
|
||||||
if (diffMoney > 0) {
|
setNewDiff(0);
|
||||||
setNewDiff(0)
|
setPaymentValueField((diffMoney / 100).toString());
|
||||||
setPaymentValueField((diffMoney / 100).toString())
|
}
|
||||||
}
|
}, [diffMoney])
|
||||||
}, [diffMoney])
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setPaymentValueField((notEnoughMoneyAmount / 100).toString());
|
setPaymentValueField((notEnoughMoneyAmount / 100).toString());
|
||||||
@ -99,10 +100,15 @@ export default function Payment() {
|
|||||||
setIsFromSquiz(true);
|
setIsFromSquiz(true);
|
||||||
setPaymentValueField((Number(params.get("dif") || "0") / 100).toString());
|
setPaymentValueField((Number(params.get("dif") || "0") / 100).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wayback = params.get("wayback");
|
||||||
|
if (wayback) setWaybackToSomeSite(wayback);
|
||||||
|
console.log(" я получил wayback = " + wayback)
|
||||||
|
|
||||||
navigate(`/payment`, {
|
navigate(`/payment`, {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
}, [ ]);
|
}, []);
|
||||||
|
|
||||||
async function handleChoosePaymentClick() {
|
async function handleChoosePaymentClick() {
|
||||||
if (!selectedPaymentMethod) {
|
if (!selectedPaymentMethod) {
|
||||||
@ -119,6 +125,7 @@ export default function Payment() {
|
|||||||
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
|
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
|
||||||
userId: userId ?? "",
|
userId: userId ?? "",
|
||||||
fromSquiz,
|
fromSquiz,
|
||||||
|
wayback: waybackToSomeSite,
|
||||||
body: {
|
body: {
|
||||||
type: selectedPaymentMethod,
|
type: selectedPaymentMethod,
|
||||||
amount: Number(
|
amount: Number(
|
||||||
@ -374,3 +381,4 @@ export default function Payment() {
|
|||||||
</SectionWrapper>
|
</SectionWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
//https://shub.pena.digital/quizpayment?action=squizpay&dif=50000&data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY4NDcxNjAxYzE0OWU0ZDI0ZWJmNTExNyIsImF1ZCI6InBlbmEiLCJpc3MiOiJwZW5hLWF1dGgtc2VydmljZSIsImlhdCI6MTc0OTQ4OTE1MywiZXhwIjoxNzU0NjczMTUzfQ.SqEXFSPzP3ugIscqLywGkjFJmFqx13zOtxGAjZQ6SzUw8w9ZXjE9uFn8VbLBMGPqeJbvcT2jRV2bB5qtqMy1T3aNuSZ9AZW0jY1hGvFB-bSrYguMV1yErLkR45SvdK2jGI6dg3p6LRqCHb2JMl8vur_KKaus3GiJlsTNNR0fhgI&userid=68471601c149e4d24ebf5117&from=AI&wayback=ai_27969
|
@ -19,13 +19,14 @@ import {
|
|||||||
import { logout } from "@root/api/auth";
|
import { logout } from "@root/api/auth";
|
||||||
import { clearCustomTariffs } from "@root/stores/customTariffs";
|
import { clearCustomTariffs } from "@root/stores/customTariffs";
|
||||||
import { clearTickets } from "@root/stores/tickets";
|
import { clearTickets } from "@root/stores/tickets";
|
||||||
import {setNotEnoughMoneyAmount} from "@stores/cart"
|
import { setNotEnoughMoneyAmount } from "@stores/cart"
|
||||||
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const action = params.get("action");
|
const action = params.get("action");
|
||||||
const dif = params.get("dif");
|
const dif = params.get("dif");
|
||||||
const token = params.get("data");
|
const token = params.get("data");
|
||||||
const userId = params.get("userid");
|
const userId = params.get("userid");
|
||||||
|
const wayback = params.get("wayback");
|
||||||
|
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
||||||
@ -36,10 +37,13 @@ export default function QuizPayment() {
|
|||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
function redirectIfSignedIn() {
|
function redirectIfSignedIn() {
|
||||||
if (!first && user?._id === userId)
|
if (!first && user?._id === userId) {
|
||||||
navigate(`/payment?action=${action}&dif=${dif}&user=${userId}`, {
|
let returnUrl = `/payment?action=${action}&dif=${dif}&user=${userId}`
|
||||||
|
if (wayback) returnUrl += `&wayback=${wayback}`
|
||||||
|
navigate(returnUrl, {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[navigate, user]
|
[navigate, user]
|
||||||
);
|
);
|
||||||
|
@ -99,9 +99,24 @@ function SupportChat() {
|
|||||||
url:
|
url:
|
||||||
process.env.REACT_APP_DOMAIN +
|
process.env.REACT_APP_DOMAIN +
|
||||||
`/heruvym/v1.0.0/ticket?ticket=${ticketId}&Authorization=${token}`,
|
`/heruvym/v1.0.0/ticket?ticket=${ticketId}&Authorization=${token}`,
|
||||||
|
|
||||||
onNewData: (ticketMessages) => {
|
onNewData: (ticketMessages) => {
|
||||||
updateSSEValue(ticketMessages);
|
console.log("SupportChat")
|
||||||
addOrUpdateMessages(ticketMessages);
|
console.log("ticketMessages")
|
||||||
|
console.log(ticketMessages)
|
||||||
|
const data = ticketMessages.filter(t => {
|
||||||
|
if (typeof t === "object" && t !== null && "event" in t && t.event !== "ping") {
|
||||||
|
console.log("---------------------------------------------------")
|
||||||
|
console.log(t)
|
||||||
|
console.log(typeof t === "object")
|
||||||
|
console.log("event" in t)
|
||||||
|
console.log(t.event !== "ping")
|
||||||
|
console.log("---------------------------------------------------")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
updateSSEValue(data);
|
||||||
|
addOrUpdateMessages(data);
|
||||||
},
|
},
|
||||||
onDisconnect: useCallback(() => {
|
onDisconnect: useCallback(() => {
|
||||||
clearMessageState();
|
clearMessageState();
|
||||||
@ -185,11 +200,11 @@ function SupportChat() {
|
|||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
}) +
|
}) +
|
||||||
" " +
|
" " +
|
||||||
createdAt.toLocaleTimeString(undefined, {
|
createdAt.toLocaleTimeString(undefined, {
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
});
|
});
|
||||||
|
|
||||||
const sendFile = async (file: File) => {
|
const sendFile = async (file: File) => {
|
||||||
if (file === undefined) return true;
|
if (file === undefined) return true;
|
||||||
@ -220,6 +235,9 @@ function SupportChat() {
|
|||||||
setDisableFileButton(false);
|
setDisableFileButton(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("messages messmessagesmessagesmessages messages")
|
||||||
|
console.log(messages)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -331,23 +349,26 @@ function SupportChat() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (
|
if (
|
||||||
message.files !== null &&
|
message?.files !== null &&
|
||||||
message.files.length > 0 &&
|
message?.files?.length > 0 &&
|
||||||
isFileImage()
|
isFileImage()
|
||||||
) {
|
) {
|
||||||
|
console.log("message NEWNEWNENWNEW _WE__WE_W_EW_E_WENWNEWNENWEWNE")
|
||||||
|
console.log(message)
|
||||||
return (
|
return (
|
||||||
<ChatImage
|
<ChatImage
|
||||||
unAuthenticated
|
unAuthenticated
|
||||||
key={message.id}
|
key={message.id}
|
||||||
file={message.files[0]}
|
file={message?.files[0]}
|
||||||
createdAt={message.created_at}
|
createdAt={message.created_at}
|
||||||
isSelf={ticket.user === message.user_id}
|
isSelf={ticket.user === message.user_id}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
message.files !== null &&
|
message?.files !== undefined &&
|
||||||
message.files.length > 0 &&
|
message?.files !== null &&
|
||||||
|
message?.files.length > 0 &&
|
||||||
isFileVideo()
|
isFileVideo()
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
|
@ -42,8 +42,6 @@ function TariffConstructor() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Object.entries(customTariffs).filter(([serviceKey]) => serviceKey === "squiz").map(([serviceKey, privileges], index) => {
|
{Object.entries(customTariffs).filter(([serviceKey]) => serviceKey === "squiz").map(([serviceKey, privileges], index) => {
|
||||||
console.log("privileges")
|
|
||||||
console.log(privileges)
|
|
||||||
return (
|
return (
|
||||||
<Box key={serviceKey}>
|
<Box key={serviceKey}>
|
||||||
<Box
|
<Box
|
||||||
|
@ -53,8 +53,6 @@ export default function TariffPrivilegeSlider({ privilege }: Props) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
function handleSliderChange(measurement: PrivilegeName) {
|
function handleSliderChange(measurement: PrivilegeName) {
|
||||||
console.log(measurement)
|
|
||||||
console.log(sliderSettingsByType)
|
|
||||||
return (value: number | number[]) => {
|
return (value: number | number[]) => {
|
||||||
|
|
||||||
if (Number(value) < Number(sliderSettingsByType[measurement]?.min)) {
|
if (Number(value) < Number(sliderSettingsByType[measurement]?.min)) {
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export { Slider } from "./slider"
|
export { Slider } from "./slider"
|
||||||
|
import Slider from "react-slick";
|
@ -104,7 +104,7 @@ export const Slider = ({ items }: SliderProps) => {
|
|||||||
sx={{ "& .slick-track": { marginLeft: marginLeft + "px", columnGap: items.length === 1 ? "0px" : "40px" } }}
|
sx={{ "& .slick-track": { marginLeft: marginLeft + "px", columnGap: items.length === 1 ? "0px" : "40px" } }}
|
||||||
ref={sliderRef}
|
ref={sliderRef}
|
||||||
>
|
>
|
||||||
{(items.length < 4 && !isMiddle && !isTablet) ||
|
{/* {(items.length < 4 && !isMiddle && !isTablet) ||
|
||||||
(items.length < 3 && isMiddle && !isTablet) ||
|
(items.length < 3 && isMiddle && !isTablet) ||
|
||||||
(items.length < 1 && isTablet) ? (
|
(items.length < 1 && isTablet) ? (
|
||||||
<Box
|
<Box
|
||||||
@ -140,7 +140,7 @@ export const Slider = ({ items }: SliderProps) => {
|
|||||||
>
|
>
|
||||||
{items}
|
{items}
|
||||||
</SliderSlick>
|
</SliderSlick>
|
||||||
)}
|
)} */}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,8 @@ export const setTicketApiPage = (apiPage: number) =>
|
|||||||
export const updateTickets = (receivedTickets: Ticket[]) => {
|
export const updateTickets = (receivedTickets: Ticket[]) => {
|
||||||
const state = useTicketStore.getState();
|
const state = useTicketStore.getState();
|
||||||
const ticketIdToTicketMap: { [ticketId: string]: Ticket } = {};
|
const ticketIdToTicketMap: { [ticketId: string]: Ticket } = {};
|
||||||
|
//@ts-ignore
|
||||||
|
// [...state.tickets, ...receivedTickets].filter(t=>!Boolean(t?.top_message.system)).forEach(
|
||||||
[...state.tickets, ...receivedTickets].forEach(
|
[...state.tickets, ...receivedTickets].forEach(
|
||||||
(ticket) => (ticketIdToTicketMap[ticket.id] = ticket)
|
(ticket) => (ticketIdToTicketMap[ticket.id] = ticket)
|
||||||
);
|
);
|
||||||
|
@ -273,7 +273,7 @@ export const sendUserData = async () => {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
isPatchingUser && patchUser(userPayload).then(([user]) => user && setUser(user)),
|
isPatchingUser && patchUser(userPayload).then(([user]) => user && setUser(user)),
|
||||||
isPatchingUserAccount && patchUserAccount(userAccountPayload).then(setUserAccount),
|
isPatchingUserAccount && patchUserAccount(userAccountPayload, "1.0.1").then(setUserAccount),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
73
src/support/hooks/useMessageOwnership.ts
Normal file
73
src/support/hooks/useMessageOwnership.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { TicketMessage } from "@frontend/kitui";
|
||||||
|
import { useUserStore } from "@root/stores/user";
|
||||||
|
|
||||||
|
interface UseMessageOwnershipProps {
|
||||||
|
message: TicketMessage;
|
||||||
|
sessionId?: string;
|
||||||
|
ticketUserId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseMessageOwnershipResult {
|
||||||
|
isOwnMessage: boolean;
|
||||||
|
isUnread: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMessageOwnership = ({
|
||||||
|
message,
|
||||||
|
sessionId,
|
||||||
|
ticketUserId
|
||||||
|
}: UseMessageOwnershipProps): UseMessageOwnershipResult => {
|
||||||
|
const userId = useUserStore((state) => state.user?._id);
|
||||||
|
|
||||||
|
// Определяем владельца сообщения
|
||||||
|
const isOwnMessage = (sessionId || userId || ticketUserId) === message.user_id;
|
||||||
|
|
||||||
|
// Сообщение считается непрочитанным если:
|
||||||
|
// 1. Оно не моё
|
||||||
|
// 2. Не отмечено как прочитанное (shown.me !== 1)
|
||||||
|
// 3. Не является системным (ticket_id !== "111")
|
||||||
|
const isUnread = !isOwnMessage && message.shown?.me !== 1 && message.ticket_id !== "111";
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOwnMessage,
|
||||||
|
isUnread
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
interface UseUnreadMessagesCountProps {
|
||||||
|
messages: TicketMessage[];
|
||||||
|
sessionId?: string;
|
||||||
|
ticketUserId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUnreadMessagesCount = ({
|
||||||
|
messages,
|
||||||
|
sessionId,
|
||||||
|
ticketUserId
|
||||||
|
}: UseUnreadMessagesCountProps): number => {
|
||||||
|
const userId = useUserStore((state) => state.user?._id);
|
||||||
|
|
||||||
|
// Считаем непрочитанные сообщения до первого прочитанного или своего
|
||||||
|
let unreadCount = 0;
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
const isOwnMessage = (sessionId || userId || ticketUserId) === message.user_id;
|
||||||
|
|
||||||
|
// Если это моё сообщение - прерываем подсчет
|
||||||
|
if (isOwnMessage) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если это чужое сообщение и оно не прочитано и не системное - увеличиваем счетчик
|
||||||
|
if (!isOwnMessage && message.shown?.me !== 1 && message.ticket_id !== "111") {
|
||||||
|
unreadCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если встретили прочитанное сообщение - прерываем подсчет
|
||||||
|
if (message.shown?.me === 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unreadCount;
|
||||||
|
};
|
@ -16,7 +16,6 @@ export function useCart(): CartData {
|
|||||||
return calcCart(cartTariffs ?? [], discounts ?? [], purchasesAmount, userId, isUserNko);
|
return calcCart(cartTariffs ?? [], discounts ?? [], purchasesAmount, userId, isUserNko);
|
||||||
}, [cartTariffs, discounts, purchasesAmount, userId, isUserNko]);
|
}, [cartTariffs, discounts, purchasesAmount, userId, isUserNko]);
|
||||||
|
|
||||||
console.log("cart ", cart)
|
|
||||||
|
|
||||||
return cart;
|
return cart;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user