Skip to content

Commit

Permalink
refactor : 로그인 페이지 분할
Browse files Browse the repository at this point in the history
  • Loading branch information
Lee-Dongwook committed Oct 19, 2024
1 parent eb4da7d commit b50d566
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 245 deletions.
167 changes: 0 additions & 167 deletions client/src/app/[id]/page.tsx

This file was deleted.

51 changes: 3 additions & 48 deletions client/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,5 @@
"use client";
import LoginPage from "@/template/LoginPage";

import { useState } from "react";
import { useRouter } from "next/router";
import API from "@/lib/api";
import { saveToken } from "@/lib/auth";

export default function LoginPage() {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const router = useRouter();

const handleLogin = async () => {
const loginData = {
email,
password,
};

try {
const { data } = await API.post("/api/auth/login", loginData);
saveToken(data.token);
router.push("/");
} catch (error) {
console.error("Login failed", error);
}
};

return (
<div className="p-4">
<h1 className="text-2xl">Login</h1>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
className="border p-2 mt-2 w-full"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
className="border p-2 mt-2 w-full"
/>
<button onClick={handleLogin} className="bg-blue-500 text-white p-2 mt-4">
Login
</button>
</div>
);
export default function Page() {
return <LoginPage />;
}
53 changes: 53 additions & 0 deletions client/src/components/Chat/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use client";

import { useEffect, useState } from "react";
import toast from "react-hot-toast";
import socket from "@/lib/socket";

interface ChatProps {
id: string;
}

export default function Chat({ id }: ChatProps) {
const [message, setMessage] = useState<string>("");
const [messages, setMessages] = useState<string[]>([]);

const sendMessage = () => {
socket.emit("send-message", message);
setMessages((prevMessages) => [...prevMessages, message]);
setMessage("");
};

useEffect(() => {
socket.on("receive-message", (message: string) => {
toast("New message received");
setMessages((prevMessages) => [...prevMessages, message]);
});

return () => {
socket.off("receive-message");
};
}, [id]);

return (
<div>
<h2 className="text-lg font-bold">Chat</h2>
<div className="bg-gray-100 p-4 h-64 overflow-y-scroll">
{messages.map((msg, index) => (
<div key={index} className="text-gray-800">
{msg}
</div>
))}
</div>
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
className="border p-2 w-full mt-2"
placeholder="Type a message..."
/>
<button onClick={sendMessage} className="bg-blue-500 text-white p-2 mt-2">
Send
</button>
</div>
);
}
94 changes: 75 additions & 19 deletions client/src/components/DocumentEditor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,86 @@
/* eslint-disable react-hooks/exhaustive-deps */
"use client";

import dynamic from "next/dynamic";
import "react-quill/dist/quill.snow.css";

const QuillNoSSRWrapper = dynamic(() => import("react-quill"), {
ssr: false,
loading: () => <p>Loading...</p>,
});
import { useEffect, useState } from "react";
import QuillEditor from "@/components/QuillEditor";
import useDebounce from "@/hook/useDebounce";
import API from "@/lib/api";
import socket from "@/lib/socket";
import {
saveDocumentLocally,
getLocalDocument,
deleteLocalDocument,
} from "@/lib/db";

interface DocumentEditorProps {
content: string;
onChange: (value: string) => void;
id: string;
}

export default function DocumentEditor({
content,
onChange,
}: DocumentEditorProps) {
export default function DocumentEditor({ id }: DocumentEditorProps) {
const [content, setContent] = useState<string>("");
const [isOffline, setIsOffline] = useState<boolean>(false);
const debouncedContent = useDebounce(content, 500);

const handleOnline = () => setIsOffline(false);
const handleOffline = () => setIsOffline(true);

const fetchDocument = async () => {
try {
const localData = await getLocalDocument(id);
if (localData) {
setContent(localData.content);
setIsOffline(true);
} else {
const { data } = await API.get(`/api/document/${id}`);
setContent(data.content);
}
} catch (error) {
console.error("Failed to fetch document:", error);
}
};

const handleChangeContent = (value: string) => {
setContent(value);
socket.emit("edit-document", id, value);
};

useEffect(() => {
fetchDocument();

window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);

return () => {
window.removeEventListener("online", handleOnline);
window.removeEventListener("offline", handleOffline);
};
}, [id]);

useEffect(() => {
if (debouncedContent) {
if (isOffline) {
saveDocumentLocally(id, debouncedContent);
} else {
API.put(`/api/document/${id}`, { content: debouncedContent })
.then(() => {
deleteLocalDocument(id);
})
.catch((error) => {
console.error("Failed to save document: ", error);
saveDocumentLocally(id, debouncedContent);
});
}
}
}, [debouncedContent, isOffline, id]);

return (
<div className="mt-4">
<QuillNoSSRWrapper
theme="snow"
value={content}
onChange={onChange}
className="bg-white p-2"
/>
{isOffline && (
<div className="bg-yellow-300 text-yellow-900 p-2 mb-2 rounded">
You are offline. Changes will be synced when you are back online.
</div>
)}
<QuillEditor value={content} onChange={handleChangeContent} />
</div>
);
}
Loading

0 comments on commit b50d566

Please sign in to comment.