diff --git a/README.md b/README.md index 1ebe379f5f423c7dcc8775d39ffd571117fb89f8..78293fb937913ec3a43009b7b04ec46ae7e57956 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,71 @@ -# React + TypeScript + Vite +# Spotiplay REST -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +Daftar Konten: +- [Deskripsi Singkat Aplikasi](#desc) +- [Tangkapan Layar Tampilan Aplikasi](#screenshot) +- [Pembagian Tugas](#assign) -Currently, two official plugins are available: +## Deskripsi Singkat Aplikasi <a name="desc"></a> -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +Anggota kelompok: +<table> + <tr> + <td align="center" colspan="3">No. Kelompok : 30</td> + </tr> + <tr> + <td align="center">NIM</td> + <td align="center">Nama</td> + <td align="center">Username</td> + </tr> + <tr> + <td align="center">13521076</td> + <td align="center">Moh. Aghna Maysan Abyan</td> + <td align="center"><a href=https://gitlab.informatika.org/AghnaAbyan>AghnaAbyan</a></td> + </tr> + <tr> + <td align="center">13521146</td> + <td align="center">Muhammad Zaki Amanullah</td> + <td align="center"><a href=https://gitlab.informatika.org/ZakiAmanullah>ZakiAmanullah</a></td> + </tr> + <tr> + <td align="center">13521155</td> + <td align="center">Kandida Edgina Gunawan</td> + <td align="center"><a href=https://gitlab.informatika.org/kandidagunawan>kandidagunawan</a></td> + </tr> +</table> -## Expanding the ESLint configuration +## Tangkapan Layar Tampilan Aplikasi <a name="screenshot"></a> +|| +|:--:| +| *Register Page* | -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +|| +|:--:| +| *Login Page* | -- Configure the top-level `parserOptions` property like this: +|| +|:--:| +| *Podcaster Page* | -```js - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json'], - tsconfigRootDir: __dirname, - }, -``` +|| +|:--:| +| *Podcast Info Page* | -- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` -- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list +|| +|:--:| +| *Manage Podcast Page* | + +|| +|:--:| +| *Manage Subscription Page* | + +## Pembagian Tugas <a name="assign"></a> +- Frontend Halaman login = 13521155 +- Frontend Halaman register = 13521155 +- Frontend Halaman navbar = 13521155 +- Frontend Halaman podcaster = 13521076, 13521146 +- Frontend Halaman podcaster list = 13521076, 13521146 +- Frontend Halaman podcaster review = 13521146 +- Frontend Halaman produce podcast = 13521146 +- Frontend Halaman subscription = 13521146 +- README.md client = 13521076 \ No newline at end of file diff --git a/screenshot/login.png b/screenshot/login.png new file mode 100644 index 0000000000000000000000000000000000000000..7b93a8a0aaad2b30f276254dd27e99ffa1101514 Binary files /dev/null and b/screenshot/login.png differ diff --git a/screenshot/managepodcast.png b/screenshot/managepodcast.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef6425e99ef242e04e437b06b4dc0c01076a002 Binary files /dev/null and b/screenshot/managepodcast.png differ diff --git a/screenshot/managesubscription.png b/screenshot/managesubscription.png new file mode 100644 index 0000000000000000000000000000000000000000..c523ccfbc653d40cb03f59952729960efac4b64d Binary files /dev/null and b/screenshot/managesubscription.png differ diff --git a/screenshot/podcaster.png b/screenshot/podcaster.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a74500e18c6dfbd82b9678ed7b3fad9c080deb Binary files /dev/null and b/screenshot/podcaster.png differ diff --git a/screenshot/podcastinfo.png b/screenshot/podcastinfo.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb204b80bf2f7eda38c7d8d1d704b48e2de0da2 Binary files /dev/null and b/screenshot/podcastinfo.png differ diff --git a/screenshot/register.png b/screenshot/register.png new file mode 100644 index 0000000000000000000000000000000000000000..33860d51eac3eeccfa85d10a96ca864a3b7769e2 Binary files /dev/null and b/screenshot/register.png differ diff --git a/src/App.tsx b/src/App.tsx index 8d655b30b94cd79705f29cb61f34a1497c5a9710..83c0b5b30e7685d58ce952e1f0aefc92b20c526b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ import "@fontsource/rubik"; import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; -import Navbar from "./components/Navbar"; +import Navbar from "./Navbar"; import { ChakraProvider, CSSReset } from "@chakra-ui/react"; import Podcaster from "./pages/Podcaster"; import ProducedPodcast from "./pages/ProducedPodcast"; diff --git a/src/components/Navbar.tsx b/src/Navbar.tsx similarity index 98% rename from src/components/Navbar.tsx rename to src/Navbar.tsx index b6b9dbfbcb72edd179d006b165588c9da54b7d6d..c6585481af96d4a17396f0ddb530a19b64224bd5 100644 --- a/src/components/Navbar.tsx +++ b/src/Navbar.tsx @@ -18,9 +18,9 @@ import { MenuGroup, } from "@chakra-ui/react"; import { HamburgerIcon, CloseIcon } from "@chakra-ui/icons"; -import spotiplayIcon from "../assets/spotiplay.svg"; +import spotiplayIcon from "./assets/spotiplay.svg"; import { useEffect, useState } from "react"; -import { User } from "../pages/Podcaster"; +import { User } from "./pages/Podcaster"; import axios from "axios"; interface Props { diff --git a/src/components/PodcasterRegister.tsx b/src/components/PodcasterRegister.tsx index c7e4a0dfe79a4320681cc2415561c2359915eb83..c943fe3c189e49bbfdcde54008e7bad961b6b87b 100644 --- a/src/components/PodcasterRegister.tsx +++ b/src/components/PodcasterRegister.tsx @@ -15,6 +15,7 @@ import { import { useHistory } from "react-router-dom"; import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; import { useState } from "react"; +import axios from "axios"; const PodcasterRegister = () => { const history = useHistory(); @@ -22,7 +23,7 @@ const PodcasterRegister = () => { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); - const [cover_art, setCoverArt] = useState(""); + const [cover_art, setCoverArt] = useState<any>(null); const [name, setName] = useState(""); const [description, setDescription] = useState(""); @@ -30,7 +31,12 @@ const PodcasterRegister = () => { const handleUsernameChange = (e) => setUsername(e.target.value); const handlePasswordChange = (e) => setPassword(e.target.value); const handleConfirmPasswordChange = (e) => setConfirmPassword(e.target.value); - const handleCoverArtChange = (e) => setCoverArt(e.target.value); + // const handleCoverArtChange = (e) => setCoverArt(e.target.value); + const handleCoverArtChange = (event: React.ChangeEvent<HTMLInputElement>) => { + if (event.target.files) { + setCoverArt(event.target.files[0]); + } + }; const handleNameChange = (e) => setName(e.target.value); const handleDescriptionChange = (e) => setDescription(e.target.value); @@ -64,35 +70,42 @@ const PodcasterRegister = () => { }; const onSubmit = async () => { - const url = "http://localhost:3000"; - const isPodcaster = true; - console.log(email); + // const url = "http://localhost:3000"; + // const isPodcaster = true; + // console.log(email); try { - const res = await fetch(`${url}/api/v1/register/podcaster`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ + const imageFormData = new FormData(); + imageFormData.append("file", cover_art); + const imageUploadResponse = await axios.post( + "http://localhost:3000/api/v1/upload", + imageFormData, + { + headers: { + "Content-Type": "multipart/form-data", + }, + withCredentials: true, + } + ); + const imageFilePath = `http://localhost:3000${imageUploadResponse.data.data.file_path}`; + const res = await axios.post( + "http://localhost:3000/api/v1/register/podcaster", + { username, email, password, - cover_art, + cover_art: imageFilePath, description, name, - isPodcaster, - }), - credentials: "include", - }); - - console.log(res); - if (!res.ok) { - const errorResponse = await res.json(); - throw new Error(errorResponse.message || "Registration failed."); - } - - const response = await res.json(); - alert("Form submitted!"); + isPodcaster: true, + }, + { + headers: { + "Content-Type": "application/json", + }, + withCredentials: true, + } + ); + alert("Registration successful!"); history.push("/login"); } catch (err) { console.error(err); @@ -195,7 +208,6 @@ const PodcasterRegister = () => { accept="image/*" border="none" padding="0" - value={cover_art} onChange={handleCoverArtChange} ></Input> </FormControl> diff --git a/src/components/ReviewerRegister.tsx b/src/components/ReviewerRegister.tsx index 676783295285f815c1e04da8bc6af0d48d2f71ad..63b4097c236690a4a958470e6d2ee64a35411d2a 100644 --- a/src/components/ReviewerRegister.tsx +++ b/src/components/ReviewerRegister.tsx @@ -14,6 +14,7 @@ import { import { useHistory } from "react-router-dom"; import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; import { useState } from "react"; +import axios from "axios"; const ReviewerRegister = () => { const history = useHistory(); @@ -21,13 +22,19 @@ const ReviewerRegister = () => { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); - const [profile_picture, setProfilePicture] = useState(""); + const [profile_picture, setProfilePicture] = useState<any>(null); const handleEmailChange = (e) => setEmail(e.target.value); const handleUsernameChange = (e) => setUsername(e.target.value); const handlePasswordChange = (e) => setPassword(e.target.value); const handleConfirmPasswordChange = (e) => setConfirmPassword(e.target.value); - const handleProfilePictureChange = (e) => setProfilePicture(e.target.value); + const handleProfilePictureChange = ( + event: React.ChangeEvent<HTMLInputElement> + ) => { + if (event.target.files) { + setProfilePicture(event.target.files[0]); + } + }; const [showPassword1, setShowPassword1] = useState(false); const [showPassword2, setShowPassword2] = useState(false); @@ -57,33 +64,38 @@ const ReviewerRegister = () => { }; const onSubmit = async () => { - const url = "http://localhost:3000"; - const isPodcaster = false; - console.log(email); try { - const res = await fetch(`${url}/api/v1/register/reviewer`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ + const imageFormData = new FormData(); + imageFormData.append("file", profile_picture); + const imageUploadResponse = await axios.post( + "http://localhost:3000/api/v1/upload", + imageFormData, + { + headers: { + "Content-Type": "multipart/form-data", + }, + withCredentials: true, + } + ); + + const imageFilePath = `http://localhost:3000${imageUploadResponse.data.data.file_path}`; + const res = await axios.post( + "http://localhost:3000/api/v1/register/reviewer", + { username, email, password, - profile_picture, - isPodcaster, - }), - credentials: "include", - }); - - console.log(res); - if (!res.ok) { - const errorResponse = await res.json(); - throw new Error(errorResponse.message || "Registration failed."); - } - - const response = await res.json(); - alert("Form submitted!"); + profile_picture: imageFilePath, + isPodcaster: false, + }, + { + headers: { + "Content-Type": "application/json", + }, + withCredentials: true, + } + ); + alert("Registration successful!"); history.push("/login"); } catch (err) { console.error(err); @@ -178,7 +190,6 @@ const ReviewerRegister = () => { accept="image/*" border="none" padding="0" - value={profile_picture} onChange={handleProfilePictureChange} ></Input> </FormControl> diff --git a/tsconfig.json b/tsconfig.json index a7fc6fbf23de2a53e36754bc4a2c306d0291d7b2..fdf671417301763be0e4eaa70336173790ada7fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src"], + "include": ["src", "src/Navbar.tsx"], "references": [{ "path": "./tsconfig.node.json" }] }