diff --git a/src/App.tsx b/src/App.tsx index 8a0f872..b67db3b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,25 +1,5 @@ -import NavBar from "./components/NavBar"; -import VideoPlayer from "./components/VideoPlayer"; -import LiveChat from "./components/LiveChat"; -import Comments from "./components/Comments"; +import Watch from "./features/watch/Watch"; export default function App() { - return ( - <> - -
-
-
- -
-
- -
-
-
- -
-
- - ); + return ; } diff --git a/src/components/LiveChat.tsx b/src/components/LiveChat.tsx deleted file mode 100644 index 7ef6130..0000000 --- a/src/components/LiveChat.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import useMessages from "../hooks/useMessages"; -import Message from "./Message"; - -export default function LiveChat() { - const messages = useMessages(); - - return ( -
- {messages.map((message) => ( - - ))} -
- ); -} diff --git a/src/components/Message.tsx b/src/components/Message.tsx deleted file mode 100644 index 9ca60a6..0000000 --- a/src/components/Message.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Message({ text }: any) { - return
{text}
; -} diff --git a/src/features/chats/LiveChat.tsx b/src/features/chats/LiveChat.tsx new file mode 100644 index 0000000..7b2bbd1 --- /dev/null +++ b/src/features/chats/LiveChat.tsx @@ -0,0 +1,52 @@ +import Message from "./Message"; + +type LiveChatProps = { + addNewMessage?: (message: string) => void; + messages: ReadonlyArray<{ + id: string; + text: string; + user: string; + timestamp: string; + }>; +}; + +export default function LiveChat({ messages, addNewMessage }: LiveChatProps) { + function handleNewMessage(e: React.FormEvent) { + e.preventDefault(); + + const form = e.currentTarget; + const formElements = form.elements as typeof form.elements & { + message: { value: string }; + }; + + addNewMessage!(formElements.message.value); + form.reset(); + } + + return ( +
+
+

Live Chat

+
+
+ {messages.map((message) => ( + + ))} +
+
+ +
+
+ ); +} diff --git a/src/features/chats/LiveChatContainer.tsx b/src/features/chats/LiveChatContainer.tsx new file mode 100644 index 0000000..8b178ff --- /dev/null +++ b/src/features/chats/LiveChatContainer.tsx @@ -0,0 +1,35 @@ +import { useState } from "react"; +import LiveChat from "./LiveChat"; + +export default function LiveChatContainer() { + const [messages, setMessages] = useState([ + { + id: "1", + text: "Hello, how are you?", + user: "John", + timestamp: "2020-01-01T00:00:00.000Z", + }, + { + id: "2", + text: "I'm fine, thank you!", + user: "John", + timestamp: "2020-01-01T00:00:00.000Z", + }, + ]); + + function handleAddNewMessage(message: string) { + setMessages((prevMessages) => { + return [ + ...prevMessages, + { + id: `${Date.now()}`, + text: message, + user: "John", + timestamp: new Date().toISOString(), + }, + ]; + }); + } + + return ; +} diff --git a/src/features/chats/LiveChatContainerRest.tsx b/src/features/chats/LiveChatContainerRest.tsx new file mode 100644 index 0000000..8b178ff --- /dev/null +++ b/src/features/chats/LiveChatContainerRest.tsx @@ -0,0 +1,35 @@ +import { useState } from "react"; +import LiveChat from "./LiveChat"; + +export default function LiveChatContainer() { + const [messages, setMessages] = useState([ + { + id: "1", + text: "Hello, how are you?", + user: "John", + timestamp: "2020-01-01T00:00:00.000Z", + }, + { + id: "2", + text: "I'm fine, thank you!", + user: "John", + timestamp: "2020-01-01T00:00:00.000Z", + }, + ]); + + function handleAddNewMessage(message: string) { + setMessages((prevMessages) => { + return [ + ...prevMessages, + { + id: `${Date.now()}`, + text: message, + user: "John", + timestamp: new Date().toISOString(), + }, + ]; + }); + } + + return ; +} diff --git a/src/features/chats/Message.tsx b/src/features/chats/Message.tsx new file mode 100644 index 0000000..0e563d8 --- /dev/null +++ b/src/features/chats/Message.tsx @@ -0,0 +1,3 @@ +export default function Message({ text }: any) { + return
{text}
; +} diff --git a/src/features/chats/MessagesProvider.tsx b/src/features/chats/MessagesProvider.tsx new file mode 100644 index 0000000..93f88fb --- /dev/null +++ b/src/features/chats/MessagesProvider.tsx @@ -0,0 +1,11 @@ +import createContextValue from "../createContextValue"; + +type MessagesValue = { + id: string; + text: string; + user: string; + timestamp: string; +}; + +export const [MessagesProvider, useMessagesValue] = + createContextValue>("MessagesProvider"); diff --git a/src/components/Comments.tsx b/src/features/comment/Comments.tsx similarity index 100% rename from src/components/Comments.tsx rename to src/features/comment/Comments.tsx diff --git a/src/components/NavBar.tsx b/src/features/components/NavBar.tsx similarity index 100% rename from src/components/NavBar.tsx rename to src/features/components/NavBar.tsx diff --git a/src/features/createContextValue.tsx b/src/features/createContextValue.tsx new file mode 100644 index 0000000..afdfcfe --- /dev/null +++ b/src/features/createContextValue.tsx @@ -0,0 +1,46 @@ +import React, { useContext, useMemo } from "react"; + +/** + * creates a Context provider and consumer hook to a provided value. + */ +export default function createContextValue( + name: string, + defaultValue: T | undefined = undefined +) { + const ValueContext = React.createContext(defaultValue); + + type ProviderProps = { + children: React.ReactNode; + value?: T; + }; + + /** + * Provides the value of the context. + * It memoizes the provided value and recompute when `value` changes. + */ + function Provider({ value, children }: ProviderProps) { + const contextValue = useMemo(() => value ?? defaultValue, [value]); + return ( + + {children} + + ); + } + + /** + * Reads the value of the context. + * Throws an error if the component is not wrapped in a Provider + * or if the context value is strictly undefined. + */ + function useValue() { + const contextValue = useContext(ValueContext); + if (contextValue === undefined) { + throw new Error( + `use ${name} must be used within a ${name} value provider` + ); + } + return contextValue; + } + + return [Provider, useValue] as const; +} diff --git a/src/components/VideoPlayer.tsx b/src/features/video-player/VideoPlayer.tsx similarity index 100% rename from src/components/VideoPlayer.tsx rename to src/features/video-player/VideoPlayer.tsx diff --git a/src/features/watch/Watch.tsx b/src/features/watch/Watch.tsx new file mode 100644 index 0000000..2d6841e --- /dev/null +++ b/src/features/watch/Watch.tsx @@ -0,0 +1,25 @@ +import NavBar from "../components/NavBar"; +import VideoPlayer from "../video-player/VideoPlayer"; +import LiveChatContainer from "../chats/LiveChatContainer"; +import Comments from "../comment/Comments"; + +export default function App() { + return ( + <> + +
+
+
+ +
+
+ +
+
+
+ +
+
+ + ); +} diff --git a/src/hooks/useMessages.ts b/src/hooks/useMessages.ts deleted file mode 100644 index 45d5dd9..0000000 --- a/src/hooks/useMessages.ts +++ /dev/null @@ -1,16 +0,0 @@ -export default function useMessages() { - return [ - { - id: 1, - text: "Hello, how are you?", - user: "John", - timestamp: "2020-01-01T00:00:00.000Z", - }, - { - id: 2, - text: "I'm fine, thank you!", - user: "John", - timestamp: "2020-01-01T00:00:00.000Z", - }, - ]; -}