Merge branch 'noah-dev'

This commit is contained in:
Noah Knapp 2025-08-02 06:23:47 +02:00
commit 1485183443
9 changed files with 154 additions and 112 deletions

View file

@ -1,10 +1,10 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './screens/Home';
import CreateStation from './screens/CreateStation';
import JoinStation from './screens/JoinStation';
import StationPage from './screens/StationPage';
import './App.css';
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./screens/Home";
import CreateStation from "./screens/CreateStation";
import JoinStation from "./screens/JoinStation";
import StationPage from "./screens/StationPage";
import "./App.css";
function App() {
return (
@ -14,7 +14,7 @@ function App() {
<Route path="/" element={<Home />} />
<Route path="/create-station" element={<CreateStation />} />
<Route path="/join-station" element={<JoinStation />} />
<Route path="/station" element={<StationPage />} />
<Route path="/station/:id" element={<StationPage />} />
</Routes>
</Router>
</div>

View file

@ -2,3 +2,7 @@ export const RADIOSTATION_URL = "http://localhost:8080/api";
export const CREATE_RADIOSTATION_ENDPOINT = "/radio-stations";
export const LIST_RADIOSTATIONS_ENDPOINT = "/radio-stations";
export const ADD_CLIENT_ENDPOINT = "/clients/connect";
export const SPOTIFY_PREMIUM_TOKEN =
"BQCEnWrYVdmta4Eekdkewazun99IuocRAyPEbwPSrHuGYgZYg7JGlXG2BLmRL6fwjzPJkrmHiqlTLSn1yqR36awA9Rv4n9dwvTBv1DjAitsuzaEVg7PtYdbUHXqP2HJJ4dDDvTtvUfWIBDY_Afa7WgY1cyRbl-p4VobNHXUR9N3Ye1qBTgH3RZ5ziIbIoNWe_JrxYvcedkvr23zXUVabOyahTgt_YdmnCWt2Iu8XT8sjhSyc8tOCqbs_KqE-Qe1WSPUCrGS8";

View file

@ -6,9 +6,10 @@ import { createStation } from "../utils/StationsCreate";
function CreateStation() {
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [joinCode, setJoinCode] = useState("");
const handleCreateStation = () => {
createStation(name, description);
setJoinCode(createStation(name, description));
};
return (
@ -28,6 +29,8 @@ function CreateStation() {
>
Create Radio Station
</button>
<p>your joinCode: {joinCode}</p>
</main>
</div>
);

View file

@ -1,33 +1,35 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import React from "react";
import { useNavigate } from "react-router-dom";
function Home() {
const navigate = useNavigate();
const handleCreateStation = () => {
navigate('/create-station');
navigate("/create-station");
};
const handleJoinStation = () => {
navigate('/join-station');
navigate("/join-station");
};
return (
<div className="home-container">
<div className="content">
<h1 className="title">Radio Station Hub</h1>
<p className="subtitle">Create or join a radio station to share music with friends</p>
<p className="subtitle">
Create or join a radio station to share music with friends
</p>
<div className="button-container">
<button
className="action-button primary"
<button
className="action-button primary"
onClick={handleCreateStation}
>
Create Radio Station
</button>
<button
className="action-button secondary"
<button
className="action-button secondary"
onClick={handleJoinStation}
>
Join Radio Station

View file

@ -7,14 +7,17 @@ function JoinStation() {
const [stations, setStations] = useState([]);
const handleJoinStation = (stationID) => {
console.log("Joining station with ID:" + stationID);
navigate("/station");
// console.log("Joining station with ID:" + stationID);
navigate(`/station/${stationID}`);
};
useEffect(() => {
console.log("Test");
getStations(getStations());
async function fetchStations() {
const result = await getStations();
setStations(result);
}
fetchStations();
}, []);
return (
@ -26,8 +29,12 @@ function JoinStation() {
<main className="join-station-content">
{stations.map((station, index) => {
return (
<div className="verify-method-section">
<text>station</text>
<div key={index}>
<p>Station Name: {station.name}</p>
<p>Station Description: {station.description}</p>
<button onClick={() => handleJoinStation(station.id)}>
join this station
</button>
</div>
);
})}

View file

@ -1,30 +1,41 @@
import React, { useState } from 'react';
import AddSongModal from './AddSongModal';
import LoginButton from '../components/LoginButton';
import { useParams } from "react-router-dom";
import React, { useState, useEffect } from "react";
import AddSongModal from "./AddSongModal";
import LoginButton from "../components/LoginButton";
import { addClientToStation } from "../utils/AddClientToStation";
function StationPage() {
const { stationID } = useParams();
const [clientToken, setClientToken] = useState("");
const [isModalOpen, setIsModalOpen] = useState(false);
const [currentSong, setCurrentSong] = useState({
title: "No song playing",
artist: "Add songs to get started",
isPlaying: false
});
const [accessDenied, setAccessDenied] = useState(true);
const [userName, setUserName] = useState("");
const [joinCode, setJoinCode] = useState("");
const auth = async () => {
try {
const token = await addClientToStation(userName, joinCode);
setClientToken(token);
setAccessDenied(false);
} catch (error) {
console.error("Auth failed:", error);
setAccessDenied(true);
}
};
if (accessDenied) {
return (
<div>
<textarea onChange={(e) => setUserName(e.target.value)} />
<textarea onChange={(e) => setJoinCode(e.target.value)} />
<button onClick={auth}>Access RadioTower</button>
</div>
);
}
// Empty song list - no songs initially
const recommendedSongs = [];
const handlePlayPause = () => {
setCurrentSong(prev => ({ ...prev, isPlaying: !prev.isPlaying }));
};
const handleNext = () => {
console.log('Next song');
};
const handlePrevious = () => {
console.log('Previous song');
};
const openModal = () => {
setIsModalOpen(true);
};
@ -48,39 +59,6 @@ function StationPage() {
<LoginButton />
</header>
<div className="media-controls-section">
<div className="current-song">
<h3>{currentSong.title}</h3>
<p>{currentSong.artist}</p>
</div>
<div className="media-controls">
<button className="control-btn" onClick={handlePrevious}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/>
</svg>
</button>
<button className="control-btn play-pause" onClick={handlePlayPause}>
{currentSong.isPlaying ? (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
</svg>
) : (
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M8 5v14l11-7z"/>
</svg>
)}
</button>
<button className="control-btn" onClick={handleNext}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/>
</svg>
</button>
</div>
</div>
<div className="songs-section">
<div className="section-header">
<h2>Song Queue</h2>
@ -88,14 +66,14 @@ function StationPage() {
Add Song
</button>
</div>
<div className="songs-list">
{recommendedSongs.length === 0 ? (
<div className="empty-songs-state">
<p>No songs in queue yet. Add some songs to get started!</p>
</div>
) : (
recommendedSongs.map(song => (
recommendedSongs.map((song) => (
<div key={song.id} className="song-item">
<div className="song-info">
<h4>{song.title}</h4>

View file

@ -0,0 +1,33 @@
import {
RADIOSTATION_URL,
ADD_CLIENT_ENDPOINT,
} from "../constants/ApiConstants";
export async function addClientToStation(username, joinCode) {
const body = {
username,
joinCode,
};
try {
const response = await fetch(RADIOSTATION_URL + ADD_CLIENT_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const data = await response.json();
if (!response.ok || !data.success) {
console.error("Failed to connect to station:", data.message);
throw new Error(data.message || "Unknown error");
}
return data.data.clientToken;
} catch (error) {
console.error("Error connecting client to station:", error);
throw error;
}
}

View file

@ -4,17 +4,22 @@ import {
} from "../constants/ApiConstants";
export async function getStations() {
fetch(RADIOSTATION_URL + LIST_RADIOSTATIONS_ENDPOINT, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((response) => response.json())
.then((data) => {
console.log("Station:", data);
})
.catch((error) => {
console.error("Error creating station:", error);
});
try {
const response = await fetch(
RADIOSTATION_URL + LIST_RADIOSTATIONS_ENDPOINT,
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
}
);
const data = await response.json();
console.log("Station:", data.data);
return data.data;
} catch (error) {
console.error("Error fetching stations:", error);
return [];
}
}

View file

@ -7,22 +7,32 @@ import {
export async function createStation(name, description) {
const body = {
name: "My Awesome Station",
description: "The best music station ever",
name: name,
description: description,
};
fetch(RADIOSTATION_URL + CREATE_RADIOSTATION_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
})
.then((response) => response.json())
.then((data) => {
console.log("Station created:", data);
})
.catch((error) => {
console.error("Error creating station:", error);
});
try {
const response = await fetch(
RADIOSTATION_URL + CREATE_RADIOSTATION_ENDPOINT,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const data = await response.json();
if (!response.ok || !data.success) {
console.error("Failed to create station:", data.message);
throw new Error(data.message || "Unknown error");
}
return data.data.station.joinCode;
} catch (error) {
console.error("Error connecting client to station:", error);
throw error;
}
}