diff --git a/src/App.fs b/src/App.fs index d245539..c53c544 100644 --- a/src/App.fs +++ b/src/App.fs @@ -3,10 +3,44 @@ open Feliz open Browser.Dom open Fable.Core.JsInterop - +open Feliz.Router importSideEffects "./index.css" - let root = ReactDOM.createRoot(document.getElementById "root") -root.render(App.Components.Counter()) \ No newline at end of file + +let menu = + Html.div [ + Html.a [ + prop.href (Router.formatPath []) + prop.text "Home" + ] + Html.a [ + prop.href (Router.formatPath ["login"]) + prop.text "Login" + ] + ] + +let homePage = + Html.div [ + menu + App.Components.Counter() + ] + +let loginPage = + Html.div [ + menu + App.Components.MaterialUiLogin() + ] + +let app = + React.router [ + router.onUrlChanged (fun url -> + match url with + | [] -> homePage + | ["login"] -> loginPage + | _ -> Html.h1 "Page not found" + ) + ] + +root.render(app) \ No newline at end of file diff --git a/src/Components.fs b/src/Components.fs index 2b065e4..b13bede 100644 --- a/src/Components.fs +++ b/src/Components.fs @@ -69,4 +69,52 @@ type Components() = prop.className "read-the-docs" prop.text " Click on the Vite, React or Fable Vite Plugin logos to learn more" ] - ] \ No newline at end of file + ] + + [] + static member MaterialUiLogin() = + let (username, setUsername) = React.useState("") + let (password, setPassword) = React.useState("") + let (message, setMessage) = React.useState("") + + let handleSubmit (e: Browser.Types.Event) = + e.preventDefault() + setMessage("Login successful!") + + Html.div [ + Html.h2 "Login" + Html.form [ + prop.onSubmit handleSubmit + prop.children [ + Html.div [ + Html.label [ + prop.htmlFor "username" + prop.text "Username" + ] + Html.input [ + prop.id "username" + prop.type' "text" + prop.value username + prop.onChange (fun (e: string) -> setUsername(e)) + ] + ] + Html.div [ + Html.label [ + prop.htmlFor "password" + prop.text "Password" + ] + Html.input [ + prop.id "password" + prop.type' "password" + prop.value password + prop.onChange (fun (e: string) -> setPassword(e)) + ] + ] + Html.button [ + prop.type' "submit" + prop.text "Submit" + ] + ] + ] + Html.p message + ] diff --git a/src/Components.test.fs b/src/Components.test.fs index 2f7e2ec..fa466b4 100644 --- a/src/Components.test.fs +++ b/src/Components.test.fs @@ -28,3 +28,23 @@ Jest.describe("Counter component", fun () -> Jest.expect(updatedButtonElement).toBeInTheDocument() ) ) + +Jest.describe("MaterialUiLogin component", fun () -> + let element = RTL.render(Components.MaterialUiLogin()) + + Jest.test("should render login form", fun () -> + let usernameLabel = element.getByText("Username") + let passwordLabel = element.getByText("Password") + let submitButton = element.getByText("Submit") + Jest.expect(usernameLabel).toBeInTheDocument() + Jest.expect(passwordLabel).toBeInTheDocument() + Jest.expect(submitButton).toBeInTheDocument() + ) + + Jest.test("should show success message on submit", fun () -> + let submitButton = element.getByText("Submit") + RTL.fireEvent.click(submitButton) + let successMessage = element.getByText("Login successful!") + Jest.expect(successMessage).toBeInTheDocument() + ) +) diff --git a/src/MaterialUiLogin.tsx b/src/MaterialUiLogin.tsx new file mode 100644 index 0000000..966b01b --- /dev/null +++ b/src/MaterialUiLogin.tsx @@ -0,0 +1,42 @@ +import React, { useState } from 'react'; + +const MaterialUiLogin = () => { + const [username, setUsername] = useState(''); + const [password, setPassword] = useState(''); + const [message, setMessage] = useState(''); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setMessage('Login successful!'); + }; + + return ( +
+

Login

+
+
+ + ) => setUsername(e.target.value)} + /> +
+
+ + ) => setPassword(e.target.value)} + /> +
+ +
+

{message}

+
+ ); +}; + +export default MaterialUiLogin;