....
This commit is contained in:
parent
388d3da866
commit
caef00bb5c
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -4,7 +4,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>new hamdast</title>
|
<title>همدست</title>
|
||||||
<meta name="theme-color" content="#23183E" />
|
<meta name="theme-color" content="#23183E" />
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
background: #23183E;
|
background: #23183E;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/assets/index-Ccau0Eyo.js"></script>
|
<script type="module" crossorigin src="/assets/index-C0TqKym5.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-xouV2fxu.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-xouV2fxu.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
||||||
17
dist/web.config
vendored
Normal file
17
dist/web.config
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<rule name="SPA Routes" stopProcessing="true">
|
||||||
|
<match url=".*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="/index.html" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>new hamdast</title>
|
<title>همدست</title>
|
||||||
<meta name="theme-color" content="#23183E" />
|
<meta name="theme-color" content="#23183E" />
|
||||||
<style>
|
<style>
|
||||||
html,
|
html,
|
||||||
|
|
|
||||||
17
public/web.config
Normal file
17
public/web.config
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<rule name="SPA Routes" stopProcessing="true">
|
||||||
|
<match url=".*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="/index.html" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
|
@ -196,7 +196,7 @@ export function CommentsModal({
|
||||||
<span className="text-xs text-gray-400">{comment.timestamp}</span>
|
<span className="text-xs text-gray-400">{comment.timestamp}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-sm text-white leading-relaxed mb-2">{comment.text}</p>
|
<p className="text-sm text-white leading-relaxed mb-2 whitespace-pre-line">{comment.text}</p>
|
||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { useNavigate, useLocation, Navigate } from "react-router-dom";
|
import { useNavigate, useLocation, Navigate } from "react-router-dom";
|
||||||
import { ChevronDown, ChevronRight, ShieldCheck } from "lucide-react";
|
import { ChevronDown, ChevronRight, ShieldCheck } from "lucide-react";
|
||||||
|
|
@ -110,6 +110,20 @@ export function LoginPage() {
|
||||||
return input.replace(/\d/g, (digit) => PERSIAN_NUMBERS[parseInt(digit, 10)]);
|
return input.replace(/\d/g, (digit) => PERSIAN_NUMBERS[parseInt(digit, 10)]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parsePhoneNumber = (input: string) => {
|
||||||
|
const digits = normalizeNumber(input).replace(/\D/g, "").slice(0, 11);
|
||||||
|
|
||||||
|
if (/^09\d{9}$/.test(digits)) {
|
||||||
|
return { error: "", serverMobile: digits };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^9\d{9}$/.test(digits)) {
|
||||||
|
return { error: "", serverMobile: `0${digits}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { error: "شماره موبایل معتبر نیست", serverMobile: "" };
|
||||||
|
};
|
||||||
|
|
||||||
const clearTimer = () => {
|
const clearTimer = () => {
|
||||||
if (timerRef.current) {
|
if (timerRef.current) {
|
||||||
clearInterval(timerRef.current);
|
clearInterval(timerRef.current);
|
||||||
|
|
@ -148,12 +162,16 @@ export function LoginPage() {
|
||||||
|
|
||||||
const handleSendCode = async (e: React.FormEvent) => {
|
const handleSendCode = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
const { error: phoneError, serverMobile } = parsePhoneNumber(phoneNumber);
|
||||||
|
if (phoneError) {
|
||||||
|
setError(phoneError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError("");
|
setError("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const normalizedPhone = normalizeNumber(phoneNumber);
|
const { response, result } = await requestSmsCode(serverMobile);
|
||||||
const { response, result } = await requestSmsCode(normalizedPhone);
|
|
||||||
|
|
||||||
if (response.ok && result.state === 0) {
|
if (response.ok && result.state === 0) {
|
||||||
setStep("code");
|
setStep("code");
|
||||||
|
|
@ -173,11 +191,15 @@ export function LoginPage() {
|
||||||
|
|
||||||
const handleVerifyCode = async (e?: React.FormEvent) => {
|
const handleVerifyCode = async (e?: React.FormEvent) => {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
|
const { error: phoneError, serverMobile } = parsePhoneNumber(phoneNumber);
|
||||||
|
if (phoneError) {
|
||||||
|
setError(phoneError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError("");
|
setError("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const normalizedPhone = normalizeNumber(phoneNumber);
|
|
||||||
const normalizedCode = normalizeNumber(code);
|
const normalizedCode = normalizeNumber(code);
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}/api/verifyloginbysms`, {
|
const response = await fetch(`${API_BASE_URL}/api/verifyloginbysms`, {
|
||||||
|
|
@ -186,7 +208,7 @@ export function LoginPage() {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
mobile: normalizedPhone,
|
mobile: serverMobile,
|
||||||
code: normalizedCode,
|
code: normalizedCode,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
@ -223,12 +245,16 @@ export function LoginPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResendCode = async () => {
|
const handleResendCode = async () => {
|
||||||
|
const { error: phoneError, serverMobile } = parsePhoneNumber(phoneNumber);
|
||||||
|
if (phoneError) {
|
||||||
|
setError(phoneError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError("");
|
setError("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const normalizedPhone = normalizeNumber(phoneNumber);
|
const { response, result } = await requestSmsCode(serverMobile);
|
||||||
const { response, result } = await requestSmsCode(normalizedPhone);
|
|
||||||
|
|
||||||
if (response.ok && result.state === 0) {
|
if (response.ok && result.state === 0) {
|
||||||
setCode("");
|
setCode("");
|
||||||
|
|
@ -394,7 +420,8 @@ export function LoginPage() {
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
autoFocus={step === "phone"}
|
autoFocus={step === "phone"}
|
||||||
value={toPersianNumber(phoneNumber)}
|
value={toPersianNumber(phoneNumber)}
|
||||||
onChange={(e) => setPhoneNumber(normalizeNumber(e.target.value))}
|
onChange={(e) => { const nextValue = normalizeNumber(e.target.value).replace(/\D/g, "").slice(0, 11); setPhoneNumber(nextValue); if (error) setError(""); }}
|
||||||
|
maxLength={11}
|
||||||
className="w-full bg-transparent text-left text-lg text-white outline-none placeholder:text-lg placeholder:text-white/45"
|
className="w-full bg-transparent text-left text-lg text-white outline-none placeholder:text-lg placeholder:text-white/45"
|
||||||
placeholder="۹۱۲ ۱۲۳ ۴۵۶۷"
|
placeholder="۹۱۲ ۱۲۳ ۴۵۶۷"
|
||||||
required
|
required
|
||||||
|
|
@ -535,3 +562,4 @@ export function LoginPage() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { useNavigate } from "react-router-dom";
|
||||||
import reactionIconShared from "../../assets/reaction-icon-shared.svg";
|
import reactionIconShared from "../../assets/reaction-icon-shared.svg";
|
||||||
import commentIconShared from "../../assets/comment-icon-shared.svg";
|
import commentIconShared from "../../assets/comment-icon-shared.svg";
|
||||||
import avatarFallbackImage from "../../assets/image 5.png";
|
import avatarFallbackImage from "../../assets/image 5.png";
|
||||||
|
import { convertBrToNewlines } from "../../utils/textFormat";
|
||||||
|
|
||||||
// PostCard با طراحی جدید - قسمت پایین بازطراحی شده + آیکون مشارکتکنندگان
|
// PostCard با طراحی جدید - قسمت پایین بازطراحی شده + آیکون مشارکتکنندگان
|
||||||
interface PostCardProps {
|
interface PostCardProps {
|
||||||
|
|
@ -59,6 +60,7 @@ export function PostCard({
|
||||||
teamMemberIds,
|
teamMemberIds,
|
||||||
preloadedTeamMembers,
|
preloadedTeamMembers,
|
||||||
}: PostCardProps) {
|
}: PostCardProps) {
|
||||||
|
const normalizedCaption = convertBrToNewlines(caption || "");
|
||||||
const COMMENTS_PAGE_SIZE = 25;
|
const COMMENTS_PAGE_SIZE = 25;
|
||||||
const postChromeStyle = {
|
const postChromeStyle = {
|
||||||
border: "1px solid transparent",
|
border: "1px solid transparent",
|
||||||
|
|
@ -419,11 +421,12 @@ export function PostCard({
|
||||||
WebkitLineClamp: expandedCaption ? "unset" : 4,
|
WebkitLineClamp: expandedCaption ? "unset" : 4,
|
||||||
WebkitBoxOrient: "vertical",
|
WebkitBoxOrient: "vertical",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
whiteSpace: "pre-line",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{caption}
|
{normalizedCaption}
|
||||||
</p>
|
</p>
|
||||||
{caption.length > 150 && (
|
{normalizedCaption.length > 150 && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setExpandedCaption(!expandedCaption)}
|
onClick={() => setExpandedCaption(!expandedCaption)}
|
||||||
className="text-xs mt-1"
|
className="text-xs mt-1"
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ export function PublicChatPage() {
|
||||||
|
|
||||||
const handleSendMessage = async (message: string) => {
|
const handleSendMessage = async (message: string) => {
|
||||||
const displayText = message.trim();
|
const displayText = message.trim();
|
||||||
const serverText = displayText.replace(/\r?\n+/g, " ").trim();
|
const serverText = displayText;
|
||||||
|
|
||||||
if (!serverText || isSending) return;
|
if (!serverText || isSending) return;
|
||||||
|
|
||||||
|
|
@ -194,22 +194,8 @@ export function PublicChatPage() {
|
||||||
const result = await loadChatList();
|
const result = await loadChatList();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const sortedItems = [...result.data].sort((a, b) => {
|
// Server returns oldest -> newest. UI should show newest first.
|
||||||
const timeA = Date.parse(a.datetime1 || "");
|
setHistoryItems([...result.data].reverse());
|
||||||
const timeB = Date.parse(b.datetime1 || "");
|
|
||||||
|
|
||||||
if (!Number.isNaN(timeA) && !Number.isNaN(timeB)) {
|
|
||||||
return timeB - timeA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
const allDatesInvalid = sortedItems.every((item) =>
|
|
||||||
Number.isNaN(Date.parse(item.datetime1 || "")),
|
|
||||||
);
|
|
||||||
|
|
||||||
setHistoryItems(allDatesInvalid ? [...result.data].reverse() : sortedItems);
|
|
||||||
} else {
|
} else {
|
||||||
console.error("Failed to load chat list:", result.message);
|
console.error("Failed to load chat list:", result.message);
|
||||||
alert(result.message || "خطا در بارگذاری تاریخچه");
|
alert(result.message || "خطا در بارگذاری تاریخچه");
|
||||||
|
|
@ -244,7 +230,13 @@ export function PublicChatPage() {
|
||||||
}, [handleHistoryClick, isLoading, isSending]);
|
}, [handleHistoryClick, isLoading, isSending]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full min-h-0 overflow-hidden">
|
<div
|
||||||
|
className="relative h-full min-h-0 overflow-hidden"
|
||||||
|
style={{
|
||||||
|
overscrollBehaviorY: "none",
|
||||||
|
touchAction: "pan-y",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto]">
|
<div className="grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto]">
|
||||||
<main className="relative min-h-0 overflow-hidden">
|
<main className="relative min-h-0 overflow-hidden">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@ export function ChatHistoryModal({
|
||||||
"calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 180px)",
|
"calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 180px)",
|
||||||
scrollbarWidth: "none",
|
scrollbarWidth: "none",
|
||||||
msOverflowStyle: "none",
|
msOverflowStyle: "none",
|
||||||
|
overscrollBehaviorY: "contain",
|
||||||
|
WebkitOverflowScrolling: "touch",
|
||||||
|
touchAction: "pan-y",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,13 @@ export function ChatMessages({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className="flex-1 overflow-y-auto px-4 pb-20"
|
className="h-full min-h-0 overflow-y-auto px-4 pb-20"
|
||||||
dir="rtl"
|
dir="rtl"
|
||||||
|
style={{
|
||||||
|
overscrollBehaviorY: "contain",
|
||||||
|
WebkitOverflowScrolling: "touch",
|
||||||
|
touchAction: "pan-y",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{messages.map((message) => {
|
{messages.map((message) => {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
// API Configuration
|
// API Configuration
|
||||||
export const API_BASE_URL = "http://141.11.1.189";
|
export const API_BASE_URL = "http://141.11.1.189";
|
||||||
|
// export const API_BASE_URL = "https://localhost:44362";
|
||||||
//export const API_BASE_URL = "https://hamdast-back2.sepehrdata.com";
|
//export const API_BASE_URL = "https://hamdast-back2.sepehrdata.com";
|
||||||
|
|
@ -50,7 +50,7 @@ export const useChatFlow = ({ workflowId, onMissionEnd }: UseChatFlowOptions): U
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayMessage = messageText.trim();
|
const displayMessage = messageText.trim();
|
||||||
const normalizedMessage = displayMessage.replace(/\r?\n+/g, " ").trim();
|
const normalizedMessage = displayMessage;
|
||||||
|
|
||||||
if (!normalizedMessage || !workflowId) {
|
if (!normalizedMessage || !workflowId) {
|
||||||
console.log("sendMessage aborted:", {
|
console.log("sendMessage aborted:", {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { API_BASE_URL } from "../config/api";
|
import { API_BASE_URL } from "../config/api";
|
||||||
|
import { convertBrToNewlines, convertNewlinesToBr } from "../utils/textFormat";
|
||||||
|
|
||||||
const AVATAR_CACHE_BUST_KEY = "avatarCacheBust";
|
const AVATAR_CACHE_BUST_KEY = "avatarCacheBust";
|
||||||
|
|
||||||
|
|
@ -82,7 +83,10 @@ const formatErrorMessage = (result: ApiResponse<any>): string => {
|
||||||
const parseFeedData = (data: string): FeedItem[] => {
|
const parseFeedData = (data: string): FeedItem[] => {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(data);
|
const parsed = JSON.parse(data);
|
||||||
const feedArray = JSON.parse(parsed.feed || "[]");
|
const feedArray = JSON.parse(parsed.feed || "[]").map((item: FeedItem) => ({
|
||||||
|
...item,
|
||||||
|
description: convertBrToNewlines(item.description || ""),
|
||||||
|
}));
|
||||||
return feedArray;
|
return feedArray;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error parsing feed data:", error);
|
console.error("Error parsing feed data:", error);
|
||||||
|
|
@ -280,7 +284,7 @@ export const saveComment = async (
|
||||||
save_comment_function: {
|
save_comment_function: {
|
||||||
mission_type: missionType,
|
mission_type: missionType,
|
||||||
mission_done_workflowID: missionDoneWorkflowID,
|
mission_done_workflowID: missionDoneWorkflowID,
|
||||||
text: text,
|
text: convertNewlinesToBr(text || ""),
|
||||||
replay_workflowID: replayWorkflowID,
|
replay_workflowID: replayWorkflowID,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
@ -373,7 +377,10 @@ export const loadComments = async (
|
||||||
|
|
||||||
if (response.ok && result.state === 0) {
|
if (response.ok && result.state === 0) {
|
||||||
const data = JSON.parse(result.data);
|
const data = JSON.parse(result.data);
|
||||||
const comments = JSON.parse(data.comments);
|
const comments = JSON.parse(data.comments).map((comment: CommentData) => ({
|
||||||
|
...comment,
|
||||||
|
comment_text: convertBrToNewlines(comment.comment_text || ""),
|
||||||
|
}));
|
||||||
return { comments };
|
return { comments };
|
||||||
} else {
|
} else {
|
||||||
console.error("Error loading comments:", result.message);
|
console.error("Error loading comments:", result.message);
|
||||||
|
|
@ -519,7 +526,11 @@ export const startMission = async (
|
||||||
if (response.ok && result.state === 0) {
|
if (response.ok && result.state === 0) {
|
||||||
const data = JSON.parse(result.data);
|
const data = JSON.parse(result.data);
|
||||||
const doingMissionArray = JSON.parse(data.doing_mission);
|
const doingMissionArray = JSON.parse(data.doing_mission);
|
||||||
const chatsArray = JSON.parse(data.chats);
|
const chatsArray = JSON.parse(data.chats).map((chat: ChatMessage) => ({
|
||||||
|
...chat,
|
||||||
|
question: convertBrToNewlines(chat.question || ""),
|
||||||
|
answer: convertBrToNewlines(chat.answer || ""),
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
doing_mission: doingMissionArray.length > 0 ? doingMissionArray[0] : null,
|
doing_mission: doingMissionArray.length > 0 ? doingMissionArray[0] : null,
|
||||||
|
|
@ -561,7 +572,7 @@ export const sendChatMessage = async (
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
chat_service_function: {
|
chat_service_function: {
|
||||||
user_message: userMessage,
|
user_message: convertNewlinesToBr(userMessage || ""),
|
||||||
mission_done_workflowID: missionDoneWorkflowID,
|
mission_done_workflowID: missionDoneWorkflowID,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -587,7 +598,7 @@ export const sendChatMessage = async (
|
||||||
const chatResponse = JSON.parse(data[keys[0]]);
|
const chatResponse = JSON.parse(data[keys[0]]);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: chatResponse.message,
|
message: convertBrToNewlines(chatResponse.message || ""),
|
||||||
actions: chatResponse.actions,
|
actions: chatResponse.actions,
|
||||||
is_mission_end: chatResponse.is_mission_end,
|
is_mission_end: chatResponse.is_mission_end,
|
||||||
};
|
};
|
||||||
|
|
@ -760,7 +771,7 @@ export const submitMission = async (
|
||||||
title: data.title || "",
|
title: data.title || "",
|
||||||
mission_type: data.mission_type || "",
|
mission_type: data.mission_type || "",
|
||||||
mission_done_workflowID: data.mission_done_workflowID || "",
|
mission_done_workflowID: data.mission_done_workflowID || "",
|
||||||
description: data.description || "",
|
description: convertNewlinesToBr(data.description || ""),
|
||||||
film: data.film || "",
|
film: data.film || "",
|
||||||
image: data.image || "",
|
image: data.image || "",
|
||||||
audio: data.audio || "",
|
audio: data.audio || "",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Profile Service - برای مدیریت پروفایل کاربر
|
// Profile Service - برای مدیریت پروفایل کاربر
|
||||||
import { API_BASE_URL } from "../config/api";
|
import { API_BASE_URL } from "../config/api";
|
||||||
import { getAccessToken } from "../utils/auth";
|
import { getAccessToken } from "../utils/auth";
|
||||||
|
import { convertBrToNewlines } from "../utils/textFormat";
|
||||||
|
|
||||||
export interface UserProfile {
|
export interface UserProfile {
|
||||||
username: string;
|
username: string;
|
||||||
|
|
@ -242,8 +243,18 @@ export const getUserProfileData = async (): Promise<UserProfileData | null> => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
challenges: parsedData.challenges ? JSON.parse(parsedData.challenges) : [],
|
challenges: parsedData.challenges ? JSON.parse(parsedData.challenges) : [],
|
||||||
coin_transaction: parsedData.coin_transaction ? JSON.parse(parsedData.coin_transaction) : [],
|
coin_transaction: parsedData.coin_transaction
|
||||||
posts: parsedData.posts ? JSON.parse(parsedData.posts) : [],
|
? JSON.parse(parsedData.coin_transaction).map((item: ProfileCoinTransaction) => ({
|
||||||
|
...item,
|
||||||
|
description: convertBrToNewlines(item.description || ""),
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
posts: parsedData.posts
|
||||||
|
? JSON.parse(parsedData.posts).map((post: ProfilePost) => ({
|
||||||
|
...post,
|
||||||
|
description: convertBrToNewlines(post.description || ""),
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,4 +263,4 @@ export const getUserProfileData = async (): Promise<UserProfileData | null> => {
|
||||||
if (import.meta.env.DEV) console.warn("خطا در دریافت دادههای پروفایل:", error);
|
if (import.meta.env.DEV) console.warn("خطا در دریافت دادههای پروفایل:", error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { API_BASE_URL } from "../config/api";
|
import { API_BASE_URL } from "../config/api";
|
||||||
|
import { convertBrToNewlines, convertNewlinesToBr } from "../utils/textFormat";
|
||||||
|
|
||||||
const getAuthToken = (): string | null => {
|
const getAuthToken = (): string | null => {
|
||||||
const accessToken = localStorage.getItem("accessToken");
|
const accessToken = localStorage.getItem("accessToken");
|
||||||
|
|
@ -129,10 +130,15 @@ export const loadChat = async (
|
||||||
// Parse the nested JSON string
|
// Parse the nested JSON string
|
||||||
const parsedData = JSON.parse(result.data);
|
const parsedData = JSON.parse(result.data);
|
||||||
const chats = JSON.parse(parsedData.chats);
|
const chats = JSON.parse(parsedData.chats);
|
||||||
|
const normalizedChats = chats.map((chat: PublicChatMessage) => ({
|
||||||
|
...chat,
|
||||||
|
question: convertBrToNewlines(chat.question || ""),
|
||||||
|
answer: convertBrToNewlines(chat.answer || ""),
|
||||||
|
}));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: chats,
|
data: normalizedChats,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
|
@ -177,7 +183,7 @@ export const sendPublicChatMessage = async (
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
public_caht_function: {
|
public_caht_function: {
|
||||||
chatlist_workflowID: chatlistWorkflowID,
|
chatlist_workflowID: chatlistWorkflowID,
|
||||||
question: question,
|
question: convertNewlinesToBr(question || ""),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
@ -191,7 +197,7 @@ export const sendPublicChatMessage = async (
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
answer: messageData.answer,
|
answer: convertBrToNewlines(messageData.answer || ""),
|
||||||
newChatlistWorkflowID: messageData.chatlist_workflowID2,
|
newChatlistWorkflowID: messageData.chatlist_workflowID2,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { FeedItem, getAvatarUrl, getFeedImageUrl, getVideoUrl, getAudioUrl, isOwnFeed, type TeamMember } from "../services/feedService";
|
import { FeedItem, getAvatarUrl, getFeedImageUrl, getVideoUrl, getAudioUrl, isOwnFeed, type TeamMember } from "../services/feedService";
|
||||||
|
import { convertBrToNewlines } from "./textFormat";
|
||||||
|
|
||||||
export interface PostCardModel {
|
export interface PostCardModel {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -63,7 +64,7 @@ export const mapFeedItemToPostCardModel = (
|
||||||
authorAvatar: getAvatarUrl(item.person_stage_id),
|
authorAvatar: getAvatarUrl(item.person_stage_id),
|
||||||
image: coverImage,
|
image: coverImage,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
caption: item.description,
|
caption: convertBrToNewlines(item.description || ""),
|
||||||
likes: item.like_count,
|
likes: item.like_count,
|
||||||
dislikes: item.dislike_count,
|
dislikes: item.dislike_count,
|
||||||
comments: item.comment_count,
|
comments: item.comment_count,
|
||||||
|
|
|
||||||
9
src/utils/textFormat.ts
Normal file
9
src/utils/textFormat.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
export const convertNewlinesToBr = (value: string): string => {
|
||||||
|
if (!value) return "";
|
||||||
|
return value.replace(/\r\n|\r|\n/g, "<br>");
|
||||||
|
};
|
||||||
|
|
||||||
|
export const convertBrToNewlines = (value: string): string => {
|
||||||
|
if (!value) return "";
|
||||||
|
return value.replace(/<br\s*\/?>/gi, "\n");
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user