Able to add artists and songs.

pull/7/head
Sander Vocke 5 years ago
parent 9e5fa87a6a
commit 7b20f62c36
  1. 1
      client/package.json
  2. 52
      client/src/App.tsx
  3. 1
      client/src/api.ts
  4. 3
      client/src/components/ArtistTable.tsx
  5. 38
      client/src/components/EditSongDialog.tsx
  6. 11
      client/yarn.lock
  7. 3
      server/package.json
  8. 11
      server/server.ts

@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@material-ui/core": "^4.11.0",
"@material-ui/lab": "^4.0.0-alpha.56",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",

@ -21,8 +21,8 @@ function App() {
name: ""
});
const fetchSongs = () => {
fetch(serverApi.ListSongsEndpoint)
const updateSongs = () => {
return fetch(serverApi.ListSongsEndpoint)
.then((response: any) => response.json())
.then((result: serverApi.ListSongsResponse) => {
setSongs(result.map((item: serverApi.ListSongsResponseItem) => {
@ -35,18 +35,29 @@ function App() {
}
const fetchArtists = () => {
fetch(serverApi.ListArtistsEndpoint)
.then((response: any) => response.json())
.then((result: serverApi.ListArtistsResponse) => {
setArtists(result.map((item: serverApi.ListArtistsResponseItem) => {
return {
name: item.name,
};
}));
return fetch(serverApi.ListArtistsEndpoint)
.then((response: any) => response.json())
.then((result: serverApi.ListArtistsResponse) => {
return result.map((item: serverApi.ListArtistsResponseItem) => {
return {
name: item.name,
id: item.id,
};
});
});
}
const updateArtists = () => {
return fetchArtists()
.then((artists: any[]) => {
setArtists(artists);
});
}
const createSong = (p:SongProperties) => {
if(!p.artistId) {
throw "Undefined artist ID for song to be created.";
}
const request:serverApi.CreateSongRequest = {
title: p.title,
artistId: p.artistId,
@ -56,7 +67,7 @@ function App() {
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(request)
};
fetch(serverApi.CreateSongEndpoint, requestOpts)
return fetch(serverApi.CreateSongEndpoint, requestOpts)
}
const createArtist = (p:ArtistProperties) => {
@ -68,7 +79,7 @@ function App() {
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(request)
};
fetch(serverApi.CreateArtistEndpoint, requestOpts)
return fetch(serverApi.CreateArtistEndpoint, requestOpts)
}
const openCreateSongDialog = () => {
@ -80,9 +91,9 @@ function App() {
}
const onSubmitCreateSongDialog = () => {
createSong(songDialogProperties);
fetchSongs();
setEditSongDialogOpen(false);
createSong(songDialogProperties)
.then(updateSongs)
.then(() => { setEditSongDialogOpen(false); })
}
const openCreateArtistDialog = () => {
@ -93,13 +104,13 @@ function App() {
}
const onSubmitCreateArtistDialog = () => {
createArtist(artistDialogProperties);
fetchArtists();
setEditArtistDialogOpen(false);
createArtist(artistDialogProperties)
.then(updateArtists)
.then(() => { setEditArtistDialogOpen(false); })
}
useEffect(fetchSongs, []);
useEffect(fetchArtists, []);
useEffect(() => { updateSongs(); }, []);
useEffect(() => { updateArtists(); }, []);
return (
<div style={{ maxWidth: '100%' }}>
@ -119,6 +130,7 @@ function App() {
onChangeSongProperties={(props:SongProperties) => setSongDialogProperties(props)}
songProperties={songDialogProperties}
onSubmit={onSubmitCreateSongDialog}
artists={artists}
/>
<EditArtistDialog
dialogOpen={editArtistDialogOpen}

@ -26,6 +26,7 @@ export const ListArtistsEndpoint = '/artist/list';
export interface ListArtistsRequest {}
export interface ListArtistsResponseItem {
name: String;
id: Number;
}
export interface ListArtistsResponse extends Array<ListArtistsResponseItem>{};
export function checkListArtistsRequest(req:any): boolean {

@ -2,7 +2,8 @@ import React from 'react';
import MaterialTable from 'material-table';
export interface Entry {
name: String
name: String,
id: Number,
}
export interface IProps {

@ -1,11 +1,17 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import { Dialog, Grid, Typography, TextField, Button } from '@material-ui/core';
import { Autocomplete } from '@material-ui/lab';
var cloneDeep = require('lodash/cloneDeep');
export interface SongProperties {
title: String,
artistId: Number,
artistId: Number | undefined,
}
export interface ArtistProperties {
name: String,
id: Number,
}
export interface IProps {
@ -14,6 +20,7 @@ export interface IProps {
onChangeSongProperties?: (props: SongProperties) => void,
songProperties: SongProperties,
onSubmit?: () => void,
artists: ArtistProperties[],
}
export default function EditSongDialog(props: IProps) {
@ -24,10 +31,10 @@ export default function EditSongDialog(props: IProps) {
props.onChangeSongProperties(p);
}
};
const onArtistChange = (artist: Number) => {
const onArtistChange = (artist: Number | undefined) => {
if (props.onChangeSongProperties) {
const p = cloneDeep(props.songProperties);
p.artistHash = artist;
p.artistId = artist;
props.onChangeSongProperties(p);
}
};
@ -49,11 +56,24 @@ export default function EditSongDialog(props: IProps) {
/>
</Grid>
<Grid item xs={12}>
<TextField
label="Artist"
value={props.songProperties.artistId}
onChange={(i: any) => onArtistChange(parseInt(i.target.value))}
fullWidth
<Autocomplete
options={props.artists}
getOptionLabel={(option) => option.name as string}
onChange={(event, newValue) => {
console.log("Change: ", newValue)
if(newValue) {
onArtistChange(newValue.id);
} else {
onArtistChange(undefined);
}
}}
renderInput={
(params) =>
<TextField {...params}
label="Artist"
fullWidth
/>
}
/>
</Grid>
</Grid>

@ -1321,6 +1321,17 @@
react-is "^16.8.0"
react-transition-group "^4.4.0"
"@material-ui/lab@^4.0.0-alpha.56":
version "4.0.0-alpha.56"
resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz#ff63080949b55b40625e056bbda05e130d216d34"
integrity sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==
dependencies:
"@babel/runtime" "^7.4.4"
"@material-ui/utils" "^4.10.2"
clsx "^1.0.4"
prop-types "^15.7.2"
react-is "^16.8.0"
"@material-ui/pickers@^3.2.2":
version "3.2.10"
resolved "https://registry.yarnpkg.com/@material-ui/pickers/-/pickers-3.2.10.tgz#19df024895876eb0ec7cd239bbaea595f703f0ae"

@ -2,8 +2,7 @@
"name": "mudbase-server",
"version": "1.0.0",
"scripts": {
"start": "ts-node server.ts",
"start:watch": "nodemon",
"start": "nodemon server.ts",
"build": "tsc"
},
"dependencies": {

@ -20,8 +20,8 @@ app.post(api.CreateSongEndpoint, (req: any, res: any) => {
const reqObject: api.CreateSongRequest = req.body;
console.log("Request create song: ", reqObject); // TODO: remove
// First check that the artist exists.
models.Song.findAll({
where: { artistId: reqObject.artistId }
models.Artist.findAll({
where: { id: reqObject.artistId }
})
.then((artist: any[]) => {
if (artist.length != 1) {
@ -32,7 +32,7 @@ app.post(api.CreateSongEndpoint, (req: any, res: any) => {
}
const song = models.Song.create({
title: reqObject.title,
artistId: reqObject.artistId
ArtistId: reqObject.artistId
});
const responseObject: api.CreateSongResponse = {
id: song.id
@ -51,12 +51,13 @@ app.get(api.ListSongsEndpoint, (req: any, res: any) => {
include: [models.Artist]
})
.then((songs: any[]) => {
console.log(songs);
const response: api.ListSongsResponse = songs.map((song: any) => {
return {
title: song.title,
id: song.id,
artistName: "", // TODO: fetch artist details
artistId: song.artistId,
artistName: song.Artist.name,
artistId: song.ArtistId,
};
});
res.send(response);

Loading…
Cancel
Save