Skip to content

Commit 397ce75

Browse files
authored
Merge pull request #61 from FSDSTR0225/feature/Cambios
Feature/cambios
2 parents f62dd23 + 811dfca commit 397ce75

File tree

4 files changed

+144
-116
lines changed

4 files changed

+144
-116
lines changed

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"dependencies": {
1313
"@stepperize/react": "^5.1.5",
1414
"@tailwindcss/vite": "^4.1.3",
15+
"browser-image-compression": "^2.0.2",
1516
"framer-motion": "^12.15.0",
1617
"pnpm": "^10.8.0",
1718
"react": "^19.0.0",

src/layout/chat/ChatPanel.jsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getMessages, getUsers, sendMessage, suscribeToMessages, unsubscribeFrom
55
import { ChatScreen } from "./components/ChatScreen";
66
import { WelcomeScreen } from "./components/WelcomeScreen";
77
import { ChatContext } from "./context/ChatContext";
8-
8+
import imageCompression from "browser-image-compression";
99

1010

1111

@@ -87,18 +87,31 @@ export default function ChatPanel({ onClose, user }) {
8787

8888

8989

90-
const handleImageChange = (e) => {
90+
const handleImageChange = async (e) => {
9191
const file = e.target.files[0];
9292
if (!file.type.startsWith("image/")) {
9393
// toast.error("Please select an image file");
9494
return;
9595
}
96+
try{
97+
const options = {
98+
maxSizeMB: 1, // Tamaño máximo en MB
99+
maxWidthOrHeight: 800, // Ancho o alto máximo
100+
useWebWorker: true, // Usar Web Worker para compresión
101+
}
102+
const compressedFile = await imageCompression(file, options);
103+
const base64 = await imageCompression.getDataUrlFromFile(compressedFile);
104+
setImagePreview(base64);
96105

97-
const reader = new FileReader();
98-
reader.onloadend = () => {
99-
setImagePreview(reader.result);
100-
};
101-
reader.readAsDataURL(file);
106+
}catch (error) {
107+
console.error("Error al comprimir la imagen:", error);
108+
}
109+
110+
// const reader = new FileReader();
111+
// reader.onloadend = () => {
112+
// setImagePreview(reader.result);
113+
// };
114+
// reader.readAsDataURL(file);
102115
};
103116

104117
const removeImage = () => {

src/layout/chat/components/ChatScreen.jsx

Lines changed: 107 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -7,126 +7,124 @@ import { CiImageOn } from 'react-icons/ci'
77
import { IoSend } from 'react-icons/io5'
88
import { formatMessageTime } from '../../../utils/utils'
99

10-
export const ChatScreen = ({ onClose, messages, messageEndRef, userSelected, profile, backToWelcome, sendMessage, fileInputRef, imagePreview, setMessage, message, removeImage, imageChange }) => {
10+
export const ChatScreen = ({ onClose, onlineUsers,messages, messageEndRef, userSelected, profile, backToWelcome, sendMessage, fileInputRef, imagePreview, setMessage, message, removeImage, imageChange }) => {
1111
return (
12-
<div className="flex flex-col h-full bg-neutral-100 rounded-xl shadow-lg overflow-hidden border border-neutral-80">
13-
{/* Encabezado */}
14-
<div className="p-4 border-b border-neutral-80 flex justify-between items-center bg-linear-130 from-[#37c84880] from-30% via-[#37c84880] via-30% to-[#0077ff80] to-70% ">
15-
<div className="flex items-center gap-4">
16-
<button className="" onClick={backToWelcome} aria-label="Close"><PiCaretLeft /></button>
17-
<AvatarImage user={userSelected} width={8} />
18-
<div>
19-
<NameUsers user={userSelected} align='items-start' classProps={"text-sm font-bold"}>
20-
<span className={`text-xs ${userSelected.role.type === "recruiter" ? "text-secondary-40" : "text-primary-50"}`}>
21-
{userSelected.role.type === "recruiter" ? "Recruiter" : "Developer"}
22-
</span>
23-
</NameUsers>
24-
25-
</div>
26-
</div>
27-
28-
<button onClick={onClose} className="text-sm cursor-pointer">
29-
30-
</button>
31-
</div>
32-
33-
{/* Lista de mensajes */}
34-
<div className="flex-1 overflow-y-auto p-3 space-y-2 bg-neutral-100">
35-
{messages.map((message) => (
36-
<div
37-
key={message._id}
38-
className={`chat ${message.senderId === profile._id ? "chat-end" : "chat-start"} `}
39-
ref={messageEndRef}>
40-
<div className="chat-image ">
41-
{
42-
message.senderId === profile._id
43-
? <AvatarImage user={profile} width={8} /> || "/avatar.png"
44-
: <AvatarImage user={userSelected} width={8} /> || "/avatar.png"
45-
}
46-
</div>
47-
<time className="text-xs opacity-50 ml-1">
48-
{formatMessageTime(message.createdAt)}
49-
</time>
50-
<div className="chat-bubble flex flex-col">
51-
{message.image && (
52-
<img
53-
src={message.image}
54-
alt="Attachment"
55-
className="sm:max-w-[200px] rounded-md mb-2"
56-
/>
57-
)}
58-
{message.text && <p>{message.text}</p>}
59-
</div>
60-
</div>
61-
))}
12+
<div className="flex flex-col h-dvh max-h-dvh bg-neutral-100 rounded-xl shadow-lg overflow-hidden border border-zinc-700">
13+
{/* Encabezado */}
14+
<div className="p-4 border-b border-neutral-80 flex justify-between items-center bg-gradient-to-r from-[#37c848cc] via-[#37c848cc] to-[#0077ffcc]">
15+
<div className="flex items-center gap-4">
16+
<button onClick={backToWelcome} aria-label="Close">
17+
<PiCaretLeft />
18+
</button>
19+
<AvatarImage user={userSelected} width={8} />
20+
<div>
21+
<NameUsers user={userSelected} classProps="text-sm font-bold" />
22+
<span className="text-xs text-zinc-200">
23+
{onlineUsers.includes(userSelected?._id) ? "online" : "offline"}
24+
</span>
6225
</div>
26+
</div>
27+
<button onClick={onClose} className="text-sm">
28+
29+
</button>
30+
</div>
6331

64-
{/* Preview de la imagen (fuera del input box) */}
65-
{imagePreview && (
66-
<div className="p-3 border-t border-zinc-800 bg-zinc-950">
67-
<div className="relative w-fit">
32+
{/* Lista de mensajes */}
33+
<div className="flex-1 overflow-y-auto p-3 space-y-2 bg-neutral-100 scroll-smooth">
34+
{messages.map((message) => (
35+
<div
36+
key={message._id}
37+
className={`chat ${message.senderId === profile._id ? "chat-end" : "chat-start"}`}
38+
>
39+
<div className="chat-image">
40+
{message.senderId === profile._id
41+
? <AvatarImage user={profile} width={8} />
42+
: <AvatarImage user={userSelected} width={8} />}
43+
</div>
44+
<time className="text-xs opacity-50 ml-1">
45+
{formatMessageTime(message.createdAt)}
46+
</time>
47+
<div className="chat-bubble flex flex-col">
48+
{message.image && (
6849
<img
69-
src={imagePreview}
70-
alt="Preview"
71-
className="w-24 h-24 object-cover rounded-lg border border-zinc-700"
50+
src={message.image}
51+
alt="Attachment"
52+
className="sm:max-w-[200px] rounded-md mb-2"
7253
/>
73-
<button
74-
onClick={removeImage}
75-
className="absolute -top-2 -right-2 w-6 h-6 rounded-full bg-zinc-800 text-white flex items-center justify-center"
76-
>
77-
<TiDelete />
78-
</button>
79-
</div>
54+
)}
55+
{message.text && <p>{message.text}</p>}
8056
</div>
81-
)}
57+
</div>
58+
))}
59+
{/* Ancla para hacer scroll al último mensaje */}
60+
<div ref={messageEndRef} />
61+
</div>
8262

83-
{/* Input y botones */}
84-
<div className="p-3 border-t border-neutral-80 bg-neutral-90 flex items-center gap-2">
85-
<form
86-
onSubmit={sendMessage}
87-
className="flex items-center justify-between bg-neutral-80 border border-neutral-50 rounded-lg px-2 py-1 space-x-2"
63+
{/* Preview de imagen (si hay) */}
64+
{imagePreview && (
65+
<div className="p-3 border-t border-zinc-800 bg-zinc-950">
66+
<div className="relative w-fit">
67+
<img
68+
src={imagePreview}
69+
alt="Preview"
70+
className="w-24 h-24 object-cover rounded-lg border border-zinc-700"
71+
/>
72+
<button
73+
onClick={removeImage}
74+
className="absolute -top-2 -right-2 w-6 h-6 rounded-full bg-zinc-800 text-white flex items-center justify-center"
8875
>
89-
{/* Campo de texto contenido dentro de su propio bloque */}
90-
<div className="flex-1">
91-
<input
92-
type="text"
93-
value={message}
94-
onChange={(e) => setMessage(e.target.value)}
95-
placeholder="Escribe un mensaje..."
96-
className="w-full bg-transparent text-sm px-2 py-1 focus:outline-none"
97-
/>
98-
</div>
99-
100-
{/* Input de imagen oculto */}
101-
<input
102-
type="file"
103-
accept="image/*"
104-
className="hidden"
105-
ref={fileInputRef}
106-
onChange={imageChange}
107-
/>
76+
<TiDelete />
77+
</button>
78+
</div>
79+
</div>
80+
)}
10881

109-
{/* Botones alineados */}
110-
<div className="flex items-center space-x-1">
111-
<button
112-
type="button"
113-
onClick={() => fileInputRef.current?.click()}
114-
className={`text-3xl hover:text-emerald-500 transition-colors ${imagePreview ? "text-primary-20" : "text-neutral-20"
115-
}`}
116-
>
117-
<CiImageOn />
118-
</button>
82+
{/* Input de texto y botones */}
83+
<div className="sticky bottom-0 left-0 right-0 p-3 border-t border-zinc-700 bg-zinc-900 flex items-center gap-2 z-10">
84+
<form
85+
onSubmit={sendMessage}
86+
className="flex items-center justify-between bg-zinc-800 border border-zinc-600 rounded-lg px-2 py-1 space-x-2 w-full"
87+
>
88+
{/* Campo de texto */}
89+
<div className="flex-1">
90+
<input
91+
type="text"
92+
value={message}
93+
onChange={(e) => setMessage(e.target.value)}
94+
placeholder="Escribe un mensaje..."
95+
className="w-full bg-transparent text-white text-sm px-2 py-1 focus:outline-none"
96+
/>
97+
</div>
11998

120-
<button
121-
type="submit"
122-
className="bg-secondary-60 hover:bg-secondary-70 p-2 rounded-md"
123-
>
124-
<IoSend size={16} />
125-
</button>
126-
</div>
127-
</form>
99+
{/* Input de imagen oculto */}
100+
<input
101+
type="file"
102+
accept="image/*"
103+
className="hidden"
104+
ref={fileInputRef}
105+
onChange={imageChange}
106+
/>
128107

108+
{/* Botones */}
109+
<div className="flex items-center space-x-1">
110+
<button
111+
type="button"
112+
onClick={() => fileInputRef.current?.click()}
113+
className={`text-xl hover:text-emerald-500 transition-colors ${
114+
imagePreview ? "text-emerald-500" : "text-zinc-400"
115+
}`}
116+
>
117+
<CiImageOn />
118+
</button>
119+
<button
120+
type="submit"
121+
className="bg-blue-600 hover:bg-blue-700 text-white p-2 rounded-md"
122+
>
123+
<IoSend size={16} />
124+
</button>
129125
</div>
130-
</div>
126+
</form>
127+
</div>
128+
</div>
131129
)
132130
}

0 commit comments

Comments
 (0)