London | 26-SDC-MAR | Jamal Laqdiem | Sprint 2 | Chat App #92
London | 26-SDC-MAR | Jamal Laqdiem | Sprint 2 | Chat App #92jamallaqdiem wants to merge 15 commits into
Conversation
feat: init full-stack typescript workspace with tailwind v4
Feat: Implement initial message fetching API and layout UI.
feat: implement ChatInput component with POST fetch and auto-scroll UX
feat: implement real-time message sync using WebSocket protocol
…nd fix auto rendering bugs
feat: implement real-time likes and dislikes logic using websockets a…
|
The spec has this requirement:
The Changelist section in the PR description would be the best place to include this info. The PR description is also a better place to include the frontend and backend links because it would make finding all info in one place easier. Can you also fix the Markdown syntax of the checkboxes in the PR description? |
|
@cjyuan Thanks for reviewing, I addressed the issues in the PR, could you have a look please? |
cjyuan
left a comment
There was a problem hiding this comment.
Code could use some documentation (comments).
A useful rule of thumb is to ask yourself whether you could still explain or figure out how the code works few months from now. If the answer is uncertain, consider adding a comment to help future readers understand the intent and reasoning behind it.
I will review this PR in several rounds. Can you addressed the current feedback first?
| const { username, text } = req.body; | ||
| if (!username || !text) { | ||
| return res.status(400).json({ | ||
| message: "Expected body to be a JSON object", | ||
| }); | ||
| } |
There was a problem hiding this comment.
It's good practice to validate all request inputs.
Note: A more robust implementation
- Should also handle the case where
req.bodyisnull, which would causeconst { text, sender } = req.body;to throw. - Should not assume
textandsenderare strings (if they existed)
In this exercise, let's assume the request is always coming from your client-side code. So no change needed.
| const messageId = Date.now(); | ||
| const timestamp = new Date().toISOString(); | ||
| const createMessages = { | ||
| id: messageId, |
There was a problem hiding this comment.
Relying on Date.now() for IDs can lead to collisions if multiple messages are processed within the same millisecond. A UUID-based approach is safer and ensures uniqueness.
| isNameSaved: boolean; | ||
| } | ||
|
|
||
| const FormInput = ({ |
There was a problem hiding this comment.
Why not name the file FormInput.tsx or name this ChatInput? Using the same name makes locating the component by its file name easier.
| const handleFormChat = async (e: React.FormEvent<HTMLFormElement>) => { | ||
| e.preventDefault(); | ||
| if (!formChat.username.trim() || !formChat.text.trim()) { | ||
| showNotification("Username and message cannot be empty!", "text-red-500"); |
There was a problem hiding this comment.
When I entered an empty string in any of the two input fields and clicked "SUBMIT", I expected to see this notification message, but I didn't see any message show up on the UI. Why?
| <main className="min-h-screen bg-slate-900 text-slate-100 flex flex-col items-center justify-center p-4 antialiased"> | ||
| <div className="w-full max-w-4xl bg-slate-800 rounded-2xl shadow-2xl border border-slate-700/50 overflow-hidden flex flex-col h-[800px]"> | ||
| {/* Header Section */} | ||
| <div className="bg-slate-800/80 backdrop-blur-md px-6 py-4 border-b border-slate-700 flex items-center justify-between"> | ||
| <div className="flex items-center space-x-3"> | ||
| <div className="w-3 h-3 bg-emerald-400 rounded-full animate-pulse" /> | ||
| <h1 className="text-xl font-bold tracking-wide bg-gradient-to-r content-box from-emerald-400 to-cyan-400 bg-clip-text text-transparent"> | ||
| Jamal's Community Chat | ||
| </h1> | ||
| </div> | ||
| <span className="text-xs font-semibold px-2.5 py-1 bg-slate-700 text-slate-300 rounded-full border border-slate-600"> | ||
| {chat.length} messages | ||
| </span> | ||
| </div> | ||
|
|
||
| {/* Chat Container */} | ||
| <div className="flex-1 overflow-y-auto p-6 space-y-4 custom-scrollbar"> | ||
| {chat.map((message) => ( |
There was a problem hiding this comment.
-
Could consider separate presentation logic from the application logic.
-
Cloud also consider implement the Chat container as a separate component.
| <div className="p-4 bg-slate-800/50 border-t border-slate-700/60 flex justify-end"> | ||
| <button | ||
| onClick={arrayMessages} | ||
| className="px-5 py-2.5 text-sm font-medium text-slate-900 bg-gradient-to-r from-emerald-400 to-cyan-400 hover:from-emerald-500 hover:to-cyan-500 rounded-xl shadow-lg shadow-emerald-500/10 hover:shadow-emerald-500/20 active:scale-[0.98] transition-all duration-150" |
There was a problem hiding this comment.
These long lists of class names, similar to inline CSS, make the code harder to read and maintain. Could you find a way to separate the styling from the JSX/HTML markup?
Note: This comment applies to all elements with lengthy class list.
Thanks for reviewing, I will add the comments and address the feedbacks. |
Self checklist
Changelist
Implementing the chat app using react typescript.
The app support additional features like:
Urls to Coolify:
Client Url
Server Url