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:
|
||||
hub:
|
||||
container_name: hub
|
||||
restart: unless-stopped
|
||||
image: $CI_REGISTRY_IMAGE/main:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||
hostname: hub
|
||||
image: gitea.pena/penaside/front-hub/main:1118
|
||||
tty: true
|
||||
|
||||
|
@ -1,14 +1,8 @@
|
||||
version: "3"
|
||||
services:
|
||||
hub:
|
||||
container_name: hub
|
||||
restart: unless-stopped
|
||||
image: $CI_REGISTRY_IMAGE/staging:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||
networks:
|
||||
- marketplace_penahub_frontend
|
||||
image: gitea.pena/penaside/front-hub/staging:$GITHUB_RUN_NUMBER
|
||||
hostname: hub
|
||||
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",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "craco start",
|
||||
"start": "NODE_OPTIONS=\"--max-old-space-size=1024\" craco start",
|
||||
"build": "craco build",
|
||||
"test": "craco test --env=node --transformIgnorePatterns \"node_modules/(?!@frontend)/\"",
|
||||
"test:cart": "vitest ./src/utils/calcCart",
|
||||
@ -16,7 +16,7 @@
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@emotion/react": "^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/material": "^5.10.14",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
@ -36,7 +36,7 @@
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-pdf": "^7.1.2",
|
||||
"react-router-dom": "^6.23.0",
|
||||
"react-slick": "^0.29.0",
|
||||
"react-slick": "^0.30.3",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"swr": "^2.2.5",
|
||||
"use-debounce": "^10.0.0",
|
||||
@ -53,7 +53,7 @@
|
||||
"@types/node": "^16.7.13",
|
||||
"@types/react": "^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/parser": "^6.9.1",
|
||||
"craco-alias": "^3.0.1",
|
||||
@ -75,5 +75,6 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ export const getTariffs = async (
|
||||
try {
|
||||
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
|
||||
method: "GET",
|
||||
url: `${API_URL}/tariff?page=${apiPage}&limit=${tariffsPerPage}`,
|
||||
url: `${API_URL}/tariff/getList?page=${apiPage}&limit=${tariffsPerPage}`,
|
||||
useToken: true,
|
||||
signal,
|
||||
});
|
||||
|
@ -77,12 +77,14 @@ export const sendFile = async (
|
||||
|
||||
export const createTicket = async (
|
||||
ticketNameField: string,
|
||||
ticketBodyField: string
|
||||
ticketBodyField: string,
|
||||
isToken?: boolean
|
||||
): Promise<[CreateTicketResponse | null, string?]> => {
|
||||
try {
|
||||
const createTicketResponse = await createTicketRequest({
|
||||
url: `${API_URL}/create`,
|
||||
body: { Title: ticketNameField, Message: ticketBodyField },
|
||||
body: { Title: ticketNameField, Message: ticketBodyField, System: false },
|
||||
useToken: isToken
|
||||
});
|
||||
|
||||
return [createTicketResponse];
|
||||
|
@ -16,15 +16,29 @@ interface PaymentBody {
|
||||
|
||||
export const sendPayment = async ({
|
||||
userId,
|
||||
wayback,
|
||||
body,
|
||||
fromSquiz,
|
||||
paymentPurpose,
|
||||
}: {
|
||||
userId: string;
|
||||
wayback: string;
|
||||
body: PaymentBody;
|
||||
fromSquiz: boolean;
|
||||
paymentPurpose: "paycart" | "replenishwallet";
|
||||
}): 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 = {
|
||||
currency: "RUB",
|
||||
bankCard: {
|
||||
@ -36,9 +50,7 @@ export const sendPayment = async ({
|
||||
},
|
||||
phoneNumber: "79000000000",
|
||||
login: "login_test",
|
||||
returnUrl: `https://${isStaging}hub.pena.digital/afterpay?from=${
|
||||
fromSquiz ? "quiz" : "hub"
|
||||
}&purpose=${paymentPurpose}&userid=${userId}`,
|
||||
returnUrl,
|
||||
...body,
|
||||
};
|
||||
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
getAuthToken,
|
||||
getMessageFromFetchError,
|
||||
throttle,
|
||||
TicketMessage,
|
||||
@ -150,12 +151,19 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
||||
}, []),
|
||||
onFetchStateChange: setUnauthTicketMessageFetchState,
|
||||
});
|
||||
console.log("sessionData")
|
||||
console.log(sessionData)
|
||||
useSSESubscription<TicketMessage>({
|
||||
enabled: sseEnabled && isActiveSSETab && Boolean(sessionData),
|
||||
url:
|
||||
process.env.REACT_APP_DOMAIN +
|
||||
`/heruvym/v1.0.0/ticket?ticket=${sessionData?.ticketId}&s=${sessionData?.sessionId}`,
|
||||
|
||||
onNewData: (ticketMessages) => {
|
||||
console.log("Chat")
|
||||
|
||||
console.log("ticketMessages useSSESubscription ")
|
||||
console.log(ticketMessages)
|
||||
const isTicketClosed = ticketMessages.some(
|
||||
(message) => message.session_id === "close"
|
||||
);
|
||||
@ -167,10 +175,14 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("under checking some close message -----------------------------------------")
|
||||
|
||||
updateSSEValue(ticketMessages);
|
||||
addOrUpdateUnauthMessages(ticketMessages);
|
||||
},
|
||||
onDisconnect: useCallback(() => {
|
||||
console.log("DISCONNECT")
|
||||
setUnauthIsPreventAutoscroll(false);
|
||||
setSseEnabled(false);
|
||||
}, []),
|
||||
@ -202,7 +214,7 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
||||
const message = getMessageFromFetchError(error);
|
||||
if (message) enqueueSnackbar(message);
|
||||
},
|
||||
onFetchStateChange: () => {},
|
||||
onFetchStateChange: () => { },
|
||||
enabled: Boolean(user),
|
||||
});
|
||||
|
||||
@ -245,12 +257,40 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const newMessages = messages.filter(({ shown }) => shown.me !== 1);
|
||||
if (open && messages.length > 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]);
|
||||
|
||||
@ -270,7 +310,9 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
||||
|
||||
const [createTicketresult, createTicketerror] = await createTicket(
|
||||
"Unauth title",
|
||||
messageField
|
||||
messageField,
|
||||
//При создании тикета, если нет у клиента токена, то хедер authorization вовсе не нужно слать
|
||||
Boolean(getAuthToken())
|
||||
);
|
||||
|
||||
if (createTicketerror) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, forwardRef } from "react";
|
||||
import { useState, useEffect, forwardRef, useMemo } from "react";
|
||||
import {
|
||||
Box,
|
||||
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(() => {
|
||||
const onResize = () => {
|
||||
if (document.fullscreenElement) {
|
||||
@ -153,7 +175,7 @@ export default function FloatingSupportChat() {
|
||||
/>
|
||||
)}
|
||||
<Badge
|
||||
badgeContent={messages.filter(({ shown }) => shown.me !== 1).length}
|
||||
badgeContent={unreadMessagesCount}
|
||||
sx={{
|
||||
"& .MuiBadge-badge": {
|
||||
display: isChatOpened ? "none" : "flex",
|
||||
|
@ -40,6 +40,7 @@ export default function ProtectedLayout() {
|
||||
process.env.REACT_APP_DOMAIN +
|
||||
`/heruvym/v1.0.0/subscribe?Authorization=${token}`,
|
||||
onNewData: (data) => {
|
||||
console.log("ProtectedLayout")
|
||||
updateSSEValue(data);
|
||||
updateTickets(data.filter((d) => Boolean(d.id)));
|
||||
setTicketCount(data.length);
|
||||
@ -63,6 +64,7 @@ export default function ProtectedLayout() {
|
||||
});
|
||||
|
||||
useAllTariffsFetcher({
|
||||
baseUrl: process.env.REACT_APP_DOMAIN + "/strator/tariff/getList",
|
||||
onSuccess: updateTariffs,
|
||||
onError: (error) => {
|
||||
const errorMessage = getMessageFromFetchError(error);
|
||||
|
@ -63,10 +63,8 @@ export default function DocumentItem({
|
||||
useEffect(() => {
|
||||
if (typeof documentUrl === 'string') {
|
||||
if (!documentUrl.includes("pena.digital")) {
|
||||
console.log(documentUrl)
|
||||
fetch(documentUrl)
|
||||
.then(e => {
|
||||
console.log(e)
|
||||
setReadyShowDocument(true)
|
||||
})
|
||||
.catch(e => console.log(e))
|
||||
|
@ -43,10 +43,8 @@ export default function DocumentUploadItem({
|
||||
useEffect(() => {
|
||||
if (typeof urlOrFile === 'string') {
|
||||
if (!urlOrFile.includes("pena.digital")) {
|
||||
console.log(documentUrl)
|
||||
fetch(documentUrl)
|
||||
.then(e => {
|
||||
console.log(e)
|
||||
setReadyShowDocument(true)
|
||||
})
|
||||
.catch(e => console.log(e))
|
||||
|
@ -20,6 +20,7 @@ export default () => {
|
||||
const userId = useUserStore((state) => state.user?._id);
|
||||
const [searchParams] = useSearchParams();
|
||||
const paymentUserId = searchParams.get("userid");
|
||||
const wayback = searchParams.get("wayback");
|
||||
|
||||
useEffect(() => {
|
||||
const from = searchParams.get("from") || "hub";
|
||||
@ -70,9 +71,10 @@ export default () => {
|
||||
const domain = (host.includes("s") ? "s" : "") + from;
|
||||
const pathname = from === "hub" ? "/tariffs" : "/list";
|
||||
|
||||
setRedirectUrl(
|
||||
`https://${domain}.pena.digital${pathname}?afterpay=${true}&userid=${userId}`
|
||||
);
|
||||
let redirect = `https://${domain}.pena.digital${pathname}?afterpay=${true}&userid=${userId}`
|
||||
if (wayback) redirect += `&wayback=${wayback}`
|
||||
|
||||
setRedirectUrl(redirect);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -133,3 +135,5 @@ export default () => {
|
||||
</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 [paymentValueField, setPaymentValueField] = useState<string>("0");
|
||||
const [paymentLink, setPaymentLink] = useState<string>("");
|
||||
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
|
||||
const location = useLocation();
|
||||
console.log("location", location);
|
||||
console.log("location", location.state);
|
||||
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
||||
const userId = useUserStore((state) => state.userId);
|
||||
const navigate = useNavigate();
|
||||
const handleCustomBackNavigation = useHistoryTracker();
|
||||
|
||||
const {diffMoney, setNewDiff} = useDiffMoney()
|
||||
|
||||
const [fromSquiz, setIsFromSquiz] = useState<boolean>(false);
|
||||
const [waybackToSomeSite, setWaybackToSomeSite] = useState<string>("");
|
||||
|
||||
|
||||
const { diffMoney, setNewDiff } = useDiffMoney()
|
||||
|
||||
const notEnoughMoneyAmount =
|
||||
(location.state?.notEnoughMoneyAmount as number) ?? 0;
|
||||
@ -83,13 +85,12 @@ export default function Payment() {
|
||||
bigDecimal.multiply(parseFloat(paymentValueField), 100)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(diffMoney)
|
||||
if (diffMoney > 0) {
|
||||
setNewDiff(0)
|
||||
setPaymentValueField((diffMoney / 100).toString())
|
||||
}
|
||||
}, [diffMoney])
|
||||
useEffect(() => {
|
||||
if (diffMoney > 0) {
|
||||
setNewDiff(0);
|
||||
setPaymentValueField((diffMoney / 100).toString());
|
||||
}
|
||||
}, [diffMoney])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setPaymentValueField((notEnoughMoneyAmount / 100).toString());
|
||||
@ -99,10 +100,15 @@ export default function Payment() {
|
||||
setIsFromSquiz(true);
|
||||
setPaymentValueField((Number(params.get("dif") || "0") / 100).toString());
|
||||
}
|
||||
|
||||
const wayback = params.get("wayback");
|
||||
if (wayback) setWaybackToSomeSite(wayback);
|
||||
console.log(" я получил wayback = " + wayback)
|
||||
|
||||
navigate(`/payment`, {
|
||||
replace: true,
|
||||
});
|
||||
}, [ ]);
|
||||
}, []);
|
||||
|
||||
async function handleChoosePaymentClick() {
|
||||
if (!selectedPaymentMethod) {
|
||||
@ -119,6 +125,7 @@ export default function Payment() {
|
||||
const [sendPaymentResponse, sendPaymentError] = await sendPayment({
|
||||
userId: userId ?? "",
|
||||
fromSquiz,
|
||||
wayback: waybackToSomeSite,
|
||||
body: {
|
||||
type: selectedPaymentMethod,
|
||||
amount: Number(
|
||||
@ -374,3 +381,4 @@ export default function Payment() {
|
||||
</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 { clearCustomTariffs } from "@root/stores/customTariffs";
|
||||
import { clearTickets } from "@root/stores/tickets";
|
||||
import {setNotEnoughMoneyAmount} from "@stores/cart"
|
||||
import { setNotEnoughMoneyAmount } from "@stores/cart"
|
||||
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const action = params.get("action");
|
||||
const dif = params.get("dif");
|
||||
const token = params.get("data");
|
||||
const userId = params.get("userid");
|
||||
const wayback = params.get("wayback");
|
||||
|
||||
let first = true;
|
||||
|
||||
@ -36,10 +37,13 @@ export default function QuizPayment() {
|
||||
|
||||
useEffect(
|
||||
function redirectIfSignedIn() {
|
||||
if (!first && user?._id === userId)
|
||||
navigate(`/payment?action=${action}&dif=${dif}&user=${userId}`, {
|
||||
if (!first && user?._id === userId) {
|
||||
let returnUrl = `/payment?action=${action}&dif=${dif}&user=${userId}`
|
||||
if (wayback) returnUrl += `&wayback=${wayback}`
|
||||
navigate(returnUrl, {
|
||||
replace: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
[navigate, user]
|
||||
);
|
||||
|
@ -99,9 +99,24 @@ function SupportChat() {
|
||||
url:
|
||||
process.env.REACT_APP_DOMAIN +
|
||||
`/heruvym/v1.0.0/ticket?ticket=${ticketId}&Authorization=${token}`,
|
||||
|
||||
onNewData: (ticketMessages) => {
|
||||
updateSSEValue(ticketMessages);
|
||||
addOrUpdateMessages(ticketMessages);
|
||||
console.log("SupportChat")
|
||||
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(() => {
|
||||
clearMessageState();
|
||||
@ -185,11 +200,11 @@ function SupportChat() {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}) +
|
||||
" " +
|
||||
createdAt.toLocaleTimeString(undefined, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
" " +
|
||||
createdAt.toLocaleTimeString(undefined, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
});
|
||||
|
||||
const sendFile = async (file: File) => {
|
||||
if (file === undefined) return true;
|
||||
@ -220,6 +235,9 @@ function SupportChat() {
|
||||
setDisableFileButton(false);
|
||||
};
|
||||
|
||||
console.log("messages messmessagesmessagesmessages messages")
|
||||
console.log(messages)
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -331,23 +349,26 @@ function SupportChat() {
|
||||
}
|
||||
};
|
||||
if (
|
||||
message.files !== null &&
|
||||
message.files.length > 0 &&
|
||||
message?.files !== null &&
|
||||
message?.files?.length > 0 &&
|
||||
isFileImage()
|
||||
) {
|
||||
console.log("message NEWNEWNENWNEW _WE__WE_W_EW_E_WENWNEWNENWEWNE")
|
||||
console.log(message)
|
||||
return (
|
||||
<ChatImage
|
||||
unAuthenticated
|
||||
key={message.id}
|
||||
file={message.files[0]}
|
||||
file={message?.files[0]}
|
||||
createdAt={message.created_at}
|
||||
isSelf={ticket.user === message.user_id}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (
|
||||
message.files !== null &&
|
||||
message.files.length > 0 &&
|
||||
message?.files !== undefined &&
|
||||
message?.files !== null &&
|
||||
message?.files.length > 0 &&
|
||||
isFileVideo()
|
||||
) {
|
||||
return (
|
||||
|
@ -42,8 +42,6 @@ function TariffConstructor() {
|
||||
}}
|
||||
>
|
||||
{Object.entries(customTariffs).filter(([serviceKey]) => serviceKey === "squiz").map(([serviceKey, privileges], index) => {
|
||||
console.log("privileges")
|
||||
console.log(privileges)
|
||||
return (
|
||||
<Box key={serviceKey}>
|
||||
<Box
|
||||
|
@ -53,8 +53,6 @@ export default function TariffPrivilegeSlider({ privilege }: Props) {
|
||||
);
|
||||
|
||||
function handleSliderChange(measurement: PrivilegeName) {
|
||||
console.log(measurement)
|
||||
console.log(sliderSettingsByType)
|
||||
return (value: number | number[]) => {
|
||||
|
||||
if (Number(value) < Number(sliderSettingsByType[measurement]?.min)) {
|
||||
|
@ -1 +1,2 @@
|
||||
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" } }}
|
||||
ref={sliderRef}
|
||||
>
|
||||
{(items.length < 4 && !isMiddle && !isTablet) ||
|
||||
{/* {(items.length < 4 && !isMiddle && !isTablet) ||
|
||||
(items.length < 3 && isMiddle && !isTablet) ||
|
||||
(items.length < 1 && isTablet) ? (
|
||||
<Box
|
||||
@ -140,7 +140,7 @@ export const Slider = ({ items }: SliderProps) => {
|
||||
>
|
||||
{items}
|
||||
</SliderSlick>
|
||||
)}
|
||||
)} */}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
@ -72,7 +72,8 @@ export const setTicketApiPage = (apiPage: number) =>
|
||||
export const updateTickets = (receivedTickets: Ticket[]) => {
|
||||
const state = useTicketStore.getState();
|
||||
const ticketIdToTicketMap: { [ticketId: string]: Ticket } = {};
|
||||
|
||||
//@ts-ignore
|
||||
// [...state.tickets, ...receivedTickets].filter(t=>!Boolean(t?.top_message.system)).forEach(
|
||||
[...state.tickets, ...receivedTickets].forEach(
|
||||
(ticket) => (ticketIdToTicketMap[ticket.id] = ticket)
|
||||
);
|
||||
|
@ -273,7 +273,7 @@ export const sendUserData = async () => {
|
||||
|
||||
await Promise.all([
|
||||
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);
|
||||
}, [cartTariffs, discounts, purchasesAmount, userId, isUserNko]);
|
||||
|
||||
console.log("cart ", cart)
|
||||
|
||||
return cart;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user