Spaces:
Running
Running
Update src/App.tsx
Browse files- src/App.tsx +5 -31
src/App.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
// src/App.tsx (نسخه نهایی
|
2 |
import React, { useEffect, useRef, useState, FC } from "react";
|
3 |
import './App.scss';
|
4 |
import { AppProvider, useAppContext, PersonalityType, PersonalityInstructions } from "./contexts/AppContext";
|
@@ -41,7 +41,6 @@ const PersonalityMenu: React.FC<{ isOpen: boolean; onClose: () => void; onSelect
|
|
41 |
return (
|
42 |
<div ref={menuRef} className="personality-popover-wrapper open">
|
43 |
<div className="popover-content">
|
44 |
-
{/* ✅ بخش جدید: پیشنمایش گوینده منتخب */}
|
45 |
<div className={cn("selected-voice-display", { speaking: volume > 0.01 })}>
|
46 |
<div className="voice-image-wrapper">
|
47 |
<img src={selectedSpeaker.imgUrl} alt={selectedSpeaker.name} />
|
@@ -50,7 +49,6 @@ const PersonalityMenu: React.FC<{ isOpen: boolean; onClose: () => void; onSelect
|
|
50 |
<p>{selectedSpeaker.desc}</p>
|
51 |
</div>
|
52 |
<hr className="menu-divider" />
|
53 |
-
|
54 |
<h4 className="menu-subtitle">انتخاب شخصیت</h4>
|
55 |
<ul>
|
56 |
{(Object.keys(personalityIcons) as PersonalityType[]).map(key => (
|
@@ -78,7 +76,7 @@ const PersonalityMenu: React.FC<{ isOpen: boolean; onClose: () => void; onSelect
|
|
78 |
// کامپوننت داخلی اصلی برنامه
|
79 |
const AppInternal: React.FC = () => {
|
80 |
const videoRef = useRef<HTMLVideoElement>(null);
|
81 |
-
const { volume, changePersonality, customUserName, customInstructions
|
82 |
const [isUserSpeaking, setIsUserSpeaking] = useState(false);
|
83 |
const [isMicActive, setIsMicActive] = useState(false);
|
84 |
const [isCamActive, setIsCamActive] = useState(false);
|
@@ -88,40 +86,21 @@ const AppInternal: React.FC = () => {
|
|
88 |
const [isCustomModalOpen, setIsCustomModalOpen] = useState(false);
|
89 |
const notificationButtonRef = useRef<HTMLButtonElement>(null);
|
90 |
const notificationPopoverRef = useRef<HTMLDivElement>(null);
|
91 |
-
const [confirmationMessage, setConfirmationMessage] = useState<string | null>(null);
|
92 |
-
|
93 |
-
// ✅ منطق جدید برای پیغام تایید
|
94 |
-
const showConfirmation = (message: string) => {
|
95 |
-
setConfirmationMessage(message);
|
96 |
-
setTimeout(() => setConfirmationMessage(null), 3000); // پیغام بعد از ۳ ثانیه محو میشود
|
97 |
-
};
|
98 |
|
|
|
99 |
const handleSelectPersonality = (p: PersonalityType) => {
|
100 |
setIsPersonalityMenuOpen(false);
|
101 |
if (p === 'custom') {
|
102 |
setIsCustomModalOpen(true);
|
103 |
} else {
|
104 |
changePersonality(p);
|
105 |
-
const personalityLabels: Record<PersonalityType, string> = { default: 'دستیار پیشفرض', teacher: 'استاد زبان', poetic: 'حس خوب', funny: 'شوخطبع', custom: 'شخصیت اختصاصی' };
|
106 |
-
showConfirmation(`شخصیت به ${personalityLabels[p]} تغییر کرد`);
|
107 |
}
|
108 |
};
|
109 |
|
110 |
const handleSaveCustom = (name: string, instructions: string) => {
|
111 |
changePersonality('custom', { name, instructions });
|
112 |
-
showConfirmation("شخصیت اختصاصی با موفقیت ذخیره شد");
|
113 |
};
|
114 |
-
|
115 |
-
// ✅ هوک برای نمایش پیغام تایید هنگام تغییر گوینده
|
116 |
-
useEffect(() => {
|
117 |
-
if(isPersonalityMenuOpen) return; // جلوگیری از نمایش هنگام باز بودن منو
|
118 |
-
const speaker = speakers.find(s => s.id === selectedVoice);
|
119 |
-
if (speaker) {
|
120 |
-
showConfirmation(`گوینده به ${speaker.name} تغییر کرد`);
|
121 |
-
}
|
122 |
-
}, [selectedVoice]);
|
123 |
-
|
124 |
-
|
125 |
useEffect(() => {
|
126 |
const handleClickOutside = (event: MouseEvent) => {
|
127 |
if (isNotificationOpen && notificationPopoverRef.current && !notificationPopoverRef.current.contains(event.target as Node) && notificationButtonRef.current && !notificationButtonRef.current.contains(event.target as Node)) setIsNotificationOpen(false);
|
@@ -154,12 +133,7 @@ const AppInternal: React.FC = () => {
|
|
154 |
<ControlTray videoRef={videoRef} onUserSpeakingChange={setIsUserSpeaking} isAppMicActive={isMicActive} onAppMicToggle={setIsMicActive} isAppCamActive={isCamActive} onAppCamToggle={setIsCamActive} currentFacingMode={currentFacingMode} onFacingModeChange={setCurrentFacingMode} />
|
155 |
</div>
|
156 |
<CustomModal isOpen={isCustomModalOpen} onClose={() => setIsCustomModalOpen(false)} onSave={handleSaveCustom} initialName={customUserName} initialInstructions={customInstructions} />
|
157 |
-
{/* ✅ JSX
|
158 |
-
{confirmationMessage && (
|
159 |
-
<div className="confirmation-toast">
|
160 |
-
{confirmationMessage}
|
161 |
-
</div>
|
162 |
-
)}
|
163 |
</>
|
164 |
);
|
165 |
};
|
|
|
1 |
+
// src/App.tsx (نسخه نهایی بدون پیغامهای تایید)
|
2 |
import React, { useEffect, useRef, useState, FC } from "react";
|
3 |
import './App.scss';
|
4 |
import { AppProvider, useAppContext, PersonalityType, PersonalityInstructions } from "./contexts/AppContext";
|
|
|
41 |
return (
|
42 |
<div ref={menuRef} className="personality-popover-wrapper open">
|
43 |
<div className="popover-content">
|
|
|
44 |
<div className={cn("selected-voice-display", { speaking: volume > 0.01 })}>
|
45 |
<div className="voice-image-wrapper">
|
46 |
<img src={selectedSpeaker.imgUrl} alt={selectedSpeaker.name} />
|
|
|
49 |
<p>{selectedSpeaker.desc}</p>
|
50 |
</div>
|
51 |
<hr className="menu-divider" />
|
|
|
52 |
<h4 className="menu-subtitle">انتخاب شخصیت</h4>
|
53 |
<ul>
|
54 |
{(Object.keys(personalityIcons) as PersonalityType[]).map(key => (
|
|
|
76 |
// کامپوننت داخلی اصلی برنامه
|
77 |
const AppInternal: React.FC = () => {
|
78 |
const videoRef = useRef<HTMLVideoElement>(null);
|
79 |
+
const { volume, changePersonality, customUserName, customInstructions } = useAppContext();
|
80 |
const [isUserSpeaking, setIsUserSpeaking] = useState(false);
|
81 |
const [isMicActive, setIsMicActive] = useState(false);
|
82 |
const [isCamActive, setIsCamActive] = useState(false);
|
|
|
86 |
const [isCustomModalOpen, setIsCustomModalOpen] = useState(false);
|
87 |
const notificationButtonRef = useRef<HTMLButtonElement>(null);
|
88 |
const notificationPopoverRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
+
// ✅ تغییر ۱: تمام منطق مربوط به پیغام تایید حذف شد
|
91 |
const handleSelectPersonality = (p: PersonalityType) => {
|
92 |
setIsPersonalityMenuOpen(false);
|
93 |
if (p === 'custom') {
|
94 |
setIsCustomModalOpen(true);
|
95 |
} else {
|
96 |
changePersonality(p);
|
|
|
|
|
97 |
}
|
98 |
};
|
99 |
|
100 |
const handleSaveCustom = (name: string, instructions: string) => {
|
101 |
changePersonality('custom', { name, instructions });
|
|
|
102 |
};
|
103 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
useEffect(() => {
|
105 |
const handleClickOutside = (event: MouseEvent) => {
|
106 |
if (isNotificationOpen && notificationPopoverRef.current && !notificationPopoverRef.current.contains(event.target as Node) && notificationButtonRef.current && !notificationButtonRef.current.contains(event.target as Node)) setIsNotificationOpen(false);
|
|
|
133 |
<ControlTray videoRef={videoRef} onUserSpeakingChange={setIsUserSpeaking} isAppMicActive={isMicActive} onAppMicToggle={setIsMicActive} isAppCamActive={isCamActive} onAppCamToggle={setIsCamActive} currentFacingMode={currentFacingMode} onFacingModeChange={setCurrentFacingMode} />
|
134 |
</div>
|
135 |
<CustomModal isOpen={isCustomModalOpen} onClose={() => setIsCustomModalOpen(false)} onSave={handleSaveCustom} initialName={customUserName} initialInstructions={customInstructions} />
|
136 |
+
{/* ✅ تغییر ۲: JSX مربوط به نمایش پیغام تایید حذف شد */}
|
|
|
|
|
|
|
|
|
|
|
137 |
</>
|
138 |
);
|
139 |
};
|