Commit 2be90194 authored by 健杭 徐's avatar 健杭 徐
Browse files

finish all

parent c48b7d0f
......@@ -98,15 +98,56 @@ func main() {
c.Next()
})
router.POST("/register", Register)
router.POST("/login", Login)
router.POST("/room/add", AddNewRoom)
router.GET("/room/list", GetRoomList)
router.POST("/room/delete", DeleteRoom)
router.POST("/room/message/add", AddMessage)
router.GET("/room/message/list", GetMessageList)
router.PUT("/room/message/update", RoomMessageUpdate)
router.PUT("/room/rename", RoomRename)
router.Run(":8080")
}
func Register(c *gin.Context) {
userName := c.Query("userName")
password := c.Query("password")
var roomId int
err := db.QueryRow(
"INSERT INTO users (username, password) VALUES ($1, $2) RETURNING user_id",
userName, password,
).Scan(&roomId)
if err != nil {
c.JSON(500, Response{Code: 500, Msg: "注册失败", Data: nil})
return
}
log.Printf("New user registered: %s with ID %d", userName, roomId)
c.JSON(200, Response{Code: 0, Msg: "注册成功", Data: nil})
}
func Login(c *gin.Context) {
userName := c.Query("userName")
password := c.Query("password")
var userId int
err := db.QueryRow(
"SELECT user_id FROM users WHERE username = $1 AND password = $2",
userName, password,
).Scan(&userId)
if err != nil {
c.JSON(401, Response{Code: 401, Msg: "账号或密码错误", Data: nil})
return
}
log.Printf("User logged in: %s with ID %d", userName, userId)
c.JSON(200, Response{Code: 0, Msg: "登录成功", Data: nil})
}
func AddNewRoom(c *gin.Context) {
var room RoomPreviewInfo
if err := c.ShouldBindJSON(&room); err != nil {
......@@ -186,27 +227,27 @@ func GetRoomList(c *gin.Context) {
}
func DeleteRoom(c *gin.Context) {
roomId, err := strconv.Atoi((c.Query("roomTd")))
if err != nil || roomId <= 0 {
c.JSON(http.StatusOK, Response{Code: 400, Msg: "Invalid ID"})
roomId := c.Query("roomId")
if roomId == "" {
c.JSON(400, Response{Code: 400, Msg: "Room ID is required", Data: nil})
return
}
result, err := db.Exec("DELETE FROM rooms WHERE roomId = $1", roomId)
_, err := db.Exec("DELETE FROM messages WHERE room_id = $1", roomId)
if err != nil {
c.JSON(http.StatusOK, Response{Code: 500, Msg: err.Error()})
c.JSON(500, Response{Code: 500, Msg: "Failed to delete messages in room: " + err.Error(), Data: nil})
return
}
rowsAffected, _ := result.RowsAffected()
if rowsAffected == 0 {
c.JSON(http.StatusOK, Response{Code: 400, Msg: "Room not found"})
_, err_ := db.Exec("DELETE FROM rooms WHERE room_id = $1", roomId)
if err_ != nil {
c.JSON(500, Response{Code: 500, Msg: "Failed to delete room: " + err_.Error(), Data: nil})
return
}
c.JSON(http.StatusOK, Response{
c.JSON(200, Response{
Code: 0,
Msg: "Room deleted",
Msg: "Room deleted successfully",
Data: nil,
})
}
......@@ -287,6 +328,34 @@ func GetMessageList(c *gin.Context) {
})
}
func RoomRename(c *gin.Context) {
roomId, err := strconv.Atoi(c.Query("roomId"))
if err != nil || roomId <= 0 {
c.JSON(http.StatusOK, Response{Code: 400, Msg: "Invalid room ID"})
return
}
var newName struct {
RoomName string `json:"roomName"`
}
if err := c.ShouldBindJSON(&newName); err != nil {
c.JSON(http.StatusBadRequest, Response{Code: 400, Msg: "Invalid input: " + err.Error(), Data: nil})
return
}
_, err = db.Exec("UPDATE rooms SET room_name = $1 WHERE room_id = $2", newName.RoomName, roomId)
if err != nil {
c.JSON(http.StatusInternalServerError, Response{Code: 500, Msg: "Failed to rename room: " + err.Error(), Data: nil})
return
}
c.JSON(http.StatusOK, Response{
Code: 0,
Msg: "Room renamed successfully",
Data: nil,
})
}
func RoomMessageUpdate(c *gin.Context) {
// 处理更新房间消息的逻辑
}
......@@ -310,6 +379,12 @@ func createTable() {
"time" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (room_id) REFERENCES rooms(room_id)
);
CREATE TABLE IF NOT EXISTS users (
user_id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(100) NOT NULL
);
`
_, err := db.Exec(query)
if err != nil {
......
......@@ -100,6 +100,7 @@
margin-bottom: 10px;
border-radius: 8px;
cursor: pointer;
border: 1px solid #ddd;
&:hover {
background-color: #e0e0e0;
......@@ -150,6 +151,53 @@
bottom: 10px;
}
}
.chat-room-menu {
position: absolute;
right: 10px;
top: 10px;
width: 20px;
background-color: white;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
z-index: 100;
text-align: center;
cursor: pointer;
}
/* Dropdown menu for actions */
.menu-dropdown {
position: absolute;
right: 6px;
top: 36px;
min-width: 160px;
background: #ffffff;
border: 1px solid #e5e7eb;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
padding: 6px 0;
display: none;
}
.menu-open {
display: block;
}
.menu-item {
width: 100%;
background: transparent;
border: none;
text-align: left;
padding: 10px 12px;
font-size: 14px;
color: #111827;
cursor: pointer;
}
.menu-item:hover {
background: #f3f4f6;
}
}
}
......@@ -161,7 +209,7 @@
display: flex;
flex-direction: column;
box-sizing: border-box;
background-image: url('../../public/backGround.jpg');
background-image: url('../public/backGround.jpg');
background-size: cover;
z-index: 2;
......
'use client';
import "./ChatRoom.css";
import styles from "./ChatRoom.module.css";
import React, { useEffect, useState } from "react";
import { useRouter } from 'next/navigation';
const backEnd:string = "http://localhost:8080";
......@@ -33,27 +34,66 @@ interface MessageProps {
}>;
}
function RoomEntry ({rooms, onRoomClick} : {rooms: RoomEntryProps[], onRoomClick: (roomId: number, roomName: string) => void}) {
function RoomEntry ({rooms, onRoomClick, onRename, onDelete} : {rooms: RoomEntryProps[], onRoomClick: (roomId: number, roomName: string) => void, onRename: (roomId: number, currentName: string) => void, onDelete: (roomId: number) => void}) {
const [openMenuFor, setOpenMenuFor] = useState<number | null>(null);
useEffect(() => {
const handleClickOutside = (e: MouseEvent) => {
const target = e.target as HTMLElement;
if (!target.closest('[data-menu="room-actions"]')) {
setOpenMenuFor(null);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
return (
<div className="chat-room-nav">
<div className="sidebar-action">
<button type="button" className="button" onClick={openOpenDiv}>
<div className="button-top">New Chat</div>
<div className="button-bottom"></div>
<div className="button-base"></div>
<div className={styles["chat-room-nav"]}>
<div className={styles["sidebar-action"]}>
<button type="button" className={styles["button"]} onClick={openOpenDiv}>
<div className={styles["button-top"]}>New Chat</div>
<div className={styles["button-bottom"]}></div>
<div className={styles["button-base"]}></div>
</button>
</div>
<div className="chat-list">
<div className={styles["chat-list"]}>
{rooms.map((room) => (
<div className="chat-item" key={room.roomId} onClick={() => onRoomClick(room.roomId, room.roomName)}>
<img src={RoomProfile} alt="Avatar" className="avatar" />
<div className="chat-info">
<h3>{room.roomName}</h3>
<span className="chat-message">
<div className={styles["chat-item"]} key={room.roomId}>
<img src={RoomProfile} alt="Avatar" className={styles["avatar"]} />
<div className={styles["chat-info"]}>
<h3 onClick={() => onRoomClick(room.roomId, room.roomName)}>{room.roomName}</h3>
<span className={styles["chat-message"]}>
{room.lastSender.Valid ? room.lastSender.String : ''}:
{room.lastContent.Valid ? room.lastContent.String : ''}</span>
<span className="chat-time">{room.lastTime.Valid ? formatTimeToHoursMinutes(room.lastTime.Time) : ''}</span>
<span className={styles["chat-time"]}>{room.lastTime.Valid ? formatTimeToHoursMinutes(room.lastTime.Time) : ''}</span>
</div>
<div
className={styles["chat-room-menu"]}
data-menu="room-actions"
onClick={(e) => {
e.stopPropagation();
setOpenMenuFor(prev => (prev === room.roomId ? null : room.roomId));
}}
aria-label="Room actions"
title="Room actions"
>
···
<div className={`${styles["menu-dropdown"]} ${openMenuFor === room.roomId ? styles["menu-open"] : ''}`}>
<button
className={styles["menu-item"]}
onClick={(e) => { e.stopPropagation(); setOpenMenuFor(null); onRename(room.roomId, room.roomName); }}
>
Rename room
</button>
<button
className={styles["menu-item"]}
onClick={(e) => { e.stopPropagation(); setOpenMenuFor(null); onDelete(room.roomId); }}
>
Delete room
</button>
</div>
</div>
</div>
))}
......@@ -65,8 +105,8 @@ function RoomEntry ({rooms, onRoomClick} : {rooms: RoomEntryProps[], onRoomClick
function formatTimeToHoursMinutes(isoString: string) {
const date = new Date(isoString);
const hours = String(date.getHours()).padStart(2, '0'); // 确保两位数
const minutes = String(date.getMinutes()).padStart(2, '0'); // 确保两位数
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
......@@ -79,12 +119,12 @@ function InputRoomNameArea({ onAddNewRoom }: { onAddNewRoom: (roomName: string)
closeOpenDiv();
}
return (
<div className="open">
<div className="roomName-input">
<div className={styles["open"]}>
<div className={styles["roomName-input"]}>
<h3>Please Enter the New Room Name</h3>
<input
type="text"
className="RoomNameInput"
className={styles["RoomNameInput"]}
placeholder="Start new chat"
value = {roomNameInput}
onChange={(e) => setRoomNameInput(e.target.value)}
......@@ -97,9 +137,9 @@ function InputRoomNameArea({ onAddNewRoom }: { onAddNewRoom: (roomName: string)
}
}}
/>
<div className="button-container">
<button className="create-button" onClick={handleAddNewRoom}>Submit</button>
<button className="cancel-button" onClick={closeOpenDiv}>Cancel</button>
<div className={styles["button-container"]}>
<button className={styles["create-button"]} onClick={handleAddNewRoom}>Submit</button>
<button className={styles["cancel-button"]} onClick={closeOpenDiv}>Cancel</button>
</div>
</div>
</div>
......@@ -107,25 +147,33 @@ function InputRoomNameArea({ onAddNewRoom }: { onAddNewRoom: (roomName: string)
}
function openOpenDiv() {
const openDiv = document.getElementsByClassName("open")[0] as HTMLDivElement;
const openDiv = document.getElementsByClassName(styles.open)[0] as HTMLDivElement | undefined;
if (openDiv) {
openDiv.style.zIndex = "1000";
const roomNameInput = document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement;
}
const roomNameInput = document.getElementsByClassName(styles.RoomNameInput)[0] as HTMLInputElement | undefined;
if (roomNameInput) {
roomNameInput.style.zIndex = "1001";
}
}
function closeOpenDiv() {
const openDiv = document.getElementsByClassName("open")[0] as HTMLDivElement;
const openDiv = document.getElementsByClassName(styles.open)[0] as HTMLDivElement | undefined;
if (openDiv) {
openDiv.style.zIndex = "0";
const roomNameInput = document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement;
}
const roomNameInput = document.getElementsByClassName(styles.RoomNameInput)[0] as HTMLInputElement | undefined;
if (roomNameInput) {
roomNameInput.style.zIndex = "0";
(document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement).value = '';
roomNameInput.value = '';
}
}
function MessageItem (props: MessageProps & { onAddNewComment: (content: string) => void}) {
const [inputValue, setInputValue] = useState("");
if (props.roomId === 0) {
return <div className="message-item">Please select a room to chat.</div>;
return <div className={styles["message-item"]}>Please select a room to chat.</div>;
}
const handlerSend = () => {
......@@ -137,30 +185,30 @@ function MessageItem (props: MessageProps & { onAddNewComment: (content: string)
setInputValue('');
}
return (
<div className="message-item">
<div className="message-header">
<img src={RoomProfile} alt="Avatar" className="avatar" />
<div className={styles["message-item"]}>
<div className={styles["message-header"]}>
<img src={RoomProfile} alt="Avatar" className={styles["avatar"]} />
<h2>{props.roomName}</h2>
</div>
<div className="message-list">
<div className={styles["message-list"]}>
{props.messages.map((msg, index) => (
<div key={index} className="message">
<img src={Profile[msg.profile]} alt={`${msg.sender}'s avatar`} className="avatar" />
<div className="message-content">
<div className="message-info">
<span className="message-sender">{msg.sender}</span>
<span className="message-time">{formatTimeToHoursMinutes(msg.time)}</span>
<div key={index} className={styles["message"]}>
<img src={Profile[msg.profile]} alt={`${msg.sender}'s avatar`} className={styles["avatar"]} />
<div className={styles["message-content"]}>
<div className={styles["message-info"]}>
<span className={styles["message-sender"]}>{msg.sender}</span>
<span className={styles["message-time"]}>{formatTimeToHoursMinutes(msg.time)}</span>
</div>
<p className="message-text">{msg.content}</p>
<p className={styles["message-text"]}>{msg.content}</p>
</div>
</div>
))}
</div>
<div className="message-input">
<div className={styles["message-input"]}>
<input
type="text"
placeholder="Type a message..."
className="Inputarea"
className={styles["Inputarea"]}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyUpCapture={
......@@ -169,9 +217,9 @@ function MessageItem (props: MessageProps & { onAddNewComment: (content: string)
handlerSend();
}
}}/>
<button className="send-button" onClick={handlerSend}>
<div className="svg-wrapper-1">
<div className="svg-wrapper">
<button className={styles["send-button"]} onClick={handlerSend}>
<div className={styles["svg-wrapper-1"]}>
<div className={styles["svg-wrapper"]}>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
......@@ -194,11 +242,13 @@ function MessageItem (props: MessageProps & { onAddNewComment: (content: string)
// From Uiverse.io by adamgiebl
}
export function ChatRoom({ userName }: { userName: string }) {
export function ChatRoomComponent({ userName }: { userName: string }) {
const [rooms, setRooms] = useState<RoomEntryProps[]>([]);
const [currentRoom, setCurrentRoom] = useState<MessageProps | null>(null);
useEffect(() => {
const ROOM_LIST_REFRESH_INTERVAL = 1000;
const MESSAGE_REFRESH_INTERVAL = 1000;
const fetchRooms = async () => {
try {
const response = await fetch(backEnd+"/room/list");
......@@ -215,39 +265,57 @@ export function ChatRoom({ userName }: { userName: string }) {
} catch (error) {
console.error("Error fetching rooms:", error);
}
}
fetchRooms();
}, []);
};
const handleRoomClick = async (roomId: number, roomName: string) => {
setCurrentRoom({
roomId: roomId,
roomName: roomName,
messages: []
});
const fetchCurrentRoomMessages = async (roomId: number) => {
if (!roomId) return;
try {
const response = await fetch(backEnd+`/room/message/list?roomId=${roomId}`)
const response = await fetch(backEnd+`/room/message/list?roomId=${roomId}`);
const result = await response.json();
debugger;
if (result.code === 0) {
setCurrentRoom({
roomId: roomId,
roomName: roomName,
setCurrentRoom(prev => {
if (!prev || prev.roomId !== roomId) return prev;
return {
...prev,
messages: result.data || []
};
});
} else {
alert(`Error fetching messages: ${result.msg}`);
}
} catch (error) {
console.error("Error fetching messages:", error);
}
};
useEffect(() => {
fetchRooms();
const roomListInterval = setInterval(() => {
fetchRooms();
}, ROOM_LIST_REFRESH_INTERVAL);
return () => clearInterval(roomListInterval);
}, []);
useEffect(() => {
if (!currentRoom?.roomId) return;
const messageInterval = setInterval(() => {
fetchCurrentRoomMessages(currentRoom.roomId);
}, MESSAGE_REFRESH_INTERVAL);
return () => clearInterval(messageInterval);
}, [currentRoom?.roomId]);
const handleRoomClick = async (roomId: number, roomName: string) => {
setCurrentRoom({
roomId: roomId,
roomName: roomName,
messages: []
});
}
} catch (error){
console.error("Error fetching messages:", error);
alert("Failed to fetch messages. See console for details.");
}
await fetchCurrentRoomMessages(roomId);
}
async function addNewRoom(roomName: string) {
......@@ -334,9 +402,51 @@ export function ChatRoom({ userName }: { userName: string }) {
}
}
const handleRename = async (roomId: number, currentName: string) => {
const newName = prompt('Enter new room name', currentName);
if (!newName || newName.trim() === '' || newName === currentName) return;
try {
const response = await fetch(backEnd + '/room/rename', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ roomId, roomName: newName })
});
const result = await response.json();
if (result.code !== 0) {
alert('Rename failed: ' + (result.msg || 'unknown error'));
return;
}
setRooms(prev => prev.map(r => r.roomId === roomId ? { ...r, roomName: newName } : r));
setCurrentRoom(prev => prev && prev.roomId === roomId ? { ...prev, roomName: newName } : prev);
} catch (err) {
console.error('Rename error', err);
alert('Rename error');
}
};
const handleDelete = async (roomId: number) => {
if (!confirm('Delete this room? This cannot be undone.')) return;
try {
const response = await fetch(backEnd + '/room/delete?roomId=' + roomId, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
const result = await response.json();
if (result.code !== 0) {
alert('Delete failed: ' + (result.msg || 'unknown error'));
return;
}
setRooms(prev => prev.filter(r => r.roomId !== roomId));
setCurrentRoom(prev => (prev && prev.roomId === roomId) ? null : prev);
} catch (err) {
console.error('Delete error', err);
alert('Delete error');
}
};
return (
<div className="chat-room">
<RoomEntry rooms={rooms} onRoomClick={handleRoomClick}/>
<div className={styles["chat-room"]}>
<RoomEntry rooms={rooms} onRoomClick={handleRoomClick} onRename={handleRename} onDelete={handleDelete}/>
<MessageItem
roomId={currentRoom?.roomId || 0}
roomName={currentRoom?.roomName || ""}
......@@ -347,3 +457,23 @@ export function ChatRoom({ userName }: { userName: string }) {
</div>
);
}
export default function ChatRoom() {
const [userName, setUserName] = useState<string | null>(null);
const router = useRouter();
useEffect(() => {
const storedUserName = localStorage.getItem('userName');
if (storedUserName) {
setUserName(storedUserName);
} else {
router.push('/');
}
}, [router]);
if (!userName) {
return <div>Loading...</div>;
}
return <ChatRoomComponent userName={userName} />;
}
\ No newline at end of file
*
/*
{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
} */
.SetName-Body
{
......@@ -16,7 +16,7 @@
min-height: 100vh;
width: 100vw;
background-size: cover;
background: url('../../public/SetbackGround.jpg') no-repeat center;
background: url('../public/SetbackGround.jpg') no-repeat center;
}
.login-box
......@@ -33,7 +33,7 @@
backdrop-filter: blur(15px);
}
h2
.setname-h2
{
font-size: 2em;
color: white;
......@@ -73,7 +73,7 @@ h2
border: none;
outline: none;
background-color: transparent;
color: white;
color: black;
font-size: 1em;
padding: 0 35px 0 5px;
}
......@@ -105,3 +105,10 @@ h2
{
background-color: lightgray;
}
.setname-repeat
{
font-size: .9em;
color: white;
margin: 20px 0 10px 0;
}
\ No newline at end of file
'use client';
import styles from"./Register.module.css"
import { MdLock, MdPerson } from "react-icons/md";
import { useState } from "react";
const backEnd:string = "http://localhost:8080";
export default function Register({ onLogin }: { onLogin: (name: string) => void }) {
const [userName, setUserName] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [passwordError, setPasswordError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setPasswordError('');
if (password !== confirmPassword) {
setPasswordError('Passwords do not match');
return;
}
if (password.length < 6) {
setPasswordError('Password must be at least 6 characters');
return;
}
try {
const response = await fetch(backEnd + '/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ userName, password }),
});
if (!response.ok) {
throw new Error('Failed to register');
}
const data = await response.json();
onLogin(data.userName);
} catch (error) {
console.error(error);
}
}
return (
<div className={styles["SetName-Body"]}>
<div className={styles["login-box"]}>
<form onSubmit={handleSubmit}>
<h2 className={styles["setname-h2"]}>Register</h2>
<div className={styles["input-box"]}>
<span className={styles["icon"]}>
<MdPerson />
</span>
<input
required
value={userName}
onChange={(e) => setUserName(e.target.value)} />
<label>Name</label>
</div>
<div className={styles["input-box"]}>
<span className={styles["icon"]}>
<MdLock />
</span>
<input
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)} />
<label>Password</label>
</div>
<div className={styles["input-box"]}>
<span className={styles["icon"]}>
<MdLock />
</span>
<input
type="password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)} />
<label>Confirm Password</label>
</div>
{passwordError && (
<div style={{ color: 'red', fontSize: '14px', marginTop: '5px', textAlign: 'center' }}>
{passwordError}
</div>
)}
<div>
<button className={styles["SetName-button"]} type="submit">Register</button>
</div>
</form>
</div>
</div>
);
}
\ No newline at end of file
/*
{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
} */
.SetName-Body
{
z-index: 2000;
display: flex;
position: absolute;
justify-content: center;
align-items: center;
min-height: 100vh;
width: 100vw;
background-size: cover;
background: url('../public/SetbackGround.jpg') no-repeat center;
}
.login-box
{
position: relative;
width: 400px;
height: 450px;
background-color: transparent;
border: 2px solid rgba(255, 255 , 255, .5);
border-radius: 20px;
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: blur(15px);
}
.setname-h2
{
font-size: 2em;
color: white;
text-align: center;
}
.input-box
{
position: relative;
width: 310px;
margin: 30px 0;
border-bottom: 2px solid white;
}
.input-box label
{
position: absolute;
top: 50%;
left: 5px;
transform: translateY(-50%);
font-size: 1em;
color: white;
pointer-events: none;
transition: .5s;
}
.input-box input:focus~label,
.input-box input:valid~label
{
top: -5px;
}
.input-box input
{
width: 100%;
height: 50px;
border: none;
outline: none;
background-color: transparent;
color: black;
font-size: 1em;
padding: 0 35px 0 5px;
}
.input-box .icon
{
position: absolute;
right: 8px;
color: white;
font-size: .9em;
line-height: 57px;
}
.SetName-button
{
outline: none;
border: none;
width: 100%;
height: 50px;
background-color: white;
border-radius: 40px;
cursor: pointer;
color: black;
font-size: 1em;
font-weight: bold;
}
.SetName-button:hover
{
background-color: lightgray;
}
.register_link
{
font-size: .9em;
text-align: center;
color: white;
margin: 20px 0 10px 0;
a
{
text-decoration: none;
color: white;
font-weight: 600;
}
a:hover
{
text-decoration: underline;
}
}
\ No newline at end of file
'use client';
import styles from"./SetName.module.css"
import { MdLock, MdPerson } from "react-icons/md";
import { useState } from "react";
import Link from "next/link";
const backEnd:string = "http://localhost:8080";
export default function SetName({ onLogin }: { onLogin: (name: string) => void }) {
const [userName, setUserName] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
e.preventDefault();
try {
const response = await fetch(`${backEnd}/login`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ userName, password })
});
const data = await response.json();
if (data.code === 0) {
onLogin(userName);
} else {
alert(data.msg);
}
} catch (error) {
console.error("Error logging in:", error);
}
}
return (
<div className={styles["SetName-Body"]}>
<div className={styles["login-box"]}>
<form onSubmit={handleSubmit}>
<h2 className={styles["setname-h2"]}>Login</h2>
<div className={styles["input-box"]}>
<span className={styles["icon"]}>
<MdPerson />
</span>
<input
required
value={userName}
onChange={(e) => setUserName(e.target.value)} />
<label>Name</label>
</div>
<div className={styles["input-box"]}>
<span className={styles["icon"]}>
<MdLock />
</span>
<input
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)} />
<label>Password</label>
</div>
<div>
<button className={styles["SetName-button"]} type="submit">Login in</button>
</div>
<div className={styles["register_link"]}>
<p>Don't have an account?<Link href="/Register">Register</Link></p>
</div>
</form>
</div>
</div>
);
}
\ No newline at end of file
'use client';
import React, { useState } from 'react';
import { ChatRoom } from "./pages/ChatRoom/ChatRoom";
import { SetName } from './pages/SetName/SetName';
import React from 'react';
import SetName from './SetName/page';
import "./globals.css";
import { useRouter } from 'next/navigation';
export default function Page() {
const [userName, setUserName] = useState('');
const router = useRouter();
const handleLogin = (name: string) => {
setUserName(name);
localStorage.setItem('userName', name);
router.push('/ChatRoom');
};
return (
<div className='root'>
{!userName ? (
<SetName onLogin={handleLogin} />
) : (
<ChatRoom userName={userName} />
)}
</div>
);
}
\ No newline at end of file
'use client';
import "./SetName.css"
import { MdPerson } from "react-icons/md";
import { useRouter } from "next/compat/router";
import { useState } from "react";
export function SetName({ onLogin }: { onLogin: (name: string) => void }) {
const [userName, setUserName] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
e.preventDefault();
if(userName.trim()) {
onLogin(userName);
}
}
return (
<div className="SetName-Body">
<div className="login-box">
<form onSubmit={handleSubmit}>
<h2>Login</h2>
<div className="input-box">
<span className="icon">
<MdPerson />
</span>
<input
required
value={userName}
onChange={(e) => setUserName(e.target.value)} />
<label>Name</label>
</div>
<div>
<button className="SetName-button" type="submit">Login in</button>
</div>
</form>
</div>
</div>
);
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment