fix voting

Seto Elkahfi committed Aug 3, 2024 at 00:38 UTC af895e57eae26b513ac774be9a9dcfeb7f3325be
7 files changed +61 -46
frontend/splitfire-desktop/app/_src/lib/requestSplitService.ts
+2 -2
@@ -1,8 +1,8 @@
1 import { AudioFile } from "../components/player/models/AudioFile"
2 import axios from "./axios"
3
4 -export default function requestSplitService(providerId: string, accessToken: string): Promise<any> {
5 - return axios.post(`/split`, { provider_id: providerId },
4 +export default function requestSplitService(songProviderId: number, accessToken: string): Promise<any> {
5 + return axios.post(`/split`, { provider_id: songProviderId },
6 {
7 headers: {
8 'Content-Type': 'application/json',
frontend/splitfire-desktop/app/_src/models/SongResponse.tsx
+1 -1
@@ -10,7 +10,7 @@ export interface SongResponse {
10 }
11
12 export interface SongProvider {
13 - id: string,
13 + id: number,
14 name: string,
15 provider_id: string,
16 provider_type: ProviderType,
frontend/splitfire-desktop/app/split/_components/button-split.tsx
+10 -10
@@ -18,21 +18,21 @@ enum State {
18 ERROR,
19 }
20
21 -export default function ButtonGenerateBackingTracks(props: {
22 - providerId: string;
21 +export default function ButtonGenerateBackingTracks({
22 + songProviderId,
23 + audioFile,
24 + aggregateVotes
25 +}: {
26 + songProviderId: number;
27 audioFile: AudioFile | null;
28 aggregateVotes: number;
29 }) {
30 +
31 const [state, setState] = useState(State.LOADED);
32 const { user } = useContext(UserContext);
33 const [goToLogin, setGoToLogin] = useState(false);
29 - const [audioFile, setAudioFile] = useState<AudioFile | null>(null);
34 const router = useRouter();
35
32 - useState(() => {
33 - setAudioFile(props.audioFile);
34 - });
35 -
36 const splitRequest = () => {
37 if (!user || !user.accessToken) {
38 setGoToLogin(true);
@@ -40,12 +40,12 @@ export default function ButtonGenerateBackingTracks(props: {
40 }
41
42 setState(State.LOADING);
43 - requestSplitService(props.providerId, user.accessToken)
43 + requestSplitService(songProviderId, user.accessToken)
44 .then((res) => {
45 console.log(res);
46 const response: SplitResponse = res.data;
47 if (response.code === HTTPStatusCode.OK) {
48 - setAudioFile(response.audio_file);
48 + audioFile = response.audio_file;
49 setState(State.LOADED);
50 } else {
51 setState(State.ERROR);
@@ -67,7 +67,7 @@ export default function ButtonGenerateBackingTracks(props: {
67 audioFile &&
68 (audioFile.status === Status.SPLITTING ||
69 audioFile.status === Status.DOWNLOADING);
70 - const isReadyToSplit = props.aggregateVotes > splitTreshold;
70 + const isReadyToSplit = aggregateVotes > splitTreshold;
71
72 if (goToLogin) {
73 router.push("/login");
frontend/splitfire-desktop/app/split/_components/votes-view.tsx
+9 -8
@@ -20,6 +20,8 @@ import LetsPlayView from "./lets-play";
20 import { invoke } from "@tauri-apps/api";
21 import { TAURI_CONTENT_SONG_BRIDGE_VOTE } from "@/app/_src/lib/tauriHandler";
22 import { useLogger } from "@/app/_src/lib/logger";
23 +import { SongProviderResponse } from "@/models/content";
24 +import { TauriResponse } from "@/models/shared";
25
26 enum State {
27 LOADING,
@@ -41,7 +43,7 @@ export interface VoteState {
43 }
44
45 type VotePayload = {
44 - songProviderId: string;
46 + songProviderId: number;
47 voteType: string;
48 accessToken: string;
49 }
@@ -51,7 +53,7 @@ export default function UpDownVotesView({
53 votes,
54 audioFile,
55 }: {
54 - songProviderId: string;
56 + songProviderId: number;
57 votes: SongProviderVote[];
58 audioFile: AudioFile | null;
59 }) {
@@ -132,9 +134,8 @@ export default function UpDownVotesView({
134 voteType: type,
135 accessToken: user.accessToken,
136 };
135 - const response = await invoke<SongBridgeResponse>(TAURI_CONTENT_SONG_BRIDGE_VOTE, payload);
136 - log.debug(response.votes);
137 - if (response.code === HTTPStatusCode.OK) {
137 + const response = await invoke<SongProviderResponse>(TAURI_CONTENT_SONG_BRIDGE_VOTE, payload);
138 + if (response.status === TauriResponse.SUCCESS) {
139 setVoteState({
140 aggregate: calculateVotes(response.votes),
141 buttonUpStyle: buttonStyle(response.votes, VoteType.UP),
@@ -146,11 +147,11 @@ export default function UpDownVotesView({
147 });
148 setState(State.LOADED);
149 } else {
149 - console.log("error");
150 + log.error("Error voting", response);
151 setState(State.ERROR);
152 }
153 } catch (error) {
153 - console.log(error);
154 + log.error(error);
155 setState(State.ERROR);
156 }
157 }
@@ -184,7 +185,7 @@ export default function UpDownVotesView({
185 );
186 const mainButton = (
187 <ButtonGenerateBackingTracks
187 - providerId={songProviderId}
188 + songProviderId={songProviderId}
189 audioFile={audioFile}
190 aggregateVotes={voteState.aggregate}
191 />
frontend/splitfire-desktop/models/content.ts
+8
@@ -1,5 +1,6 @@
1 import { SongProvider } from "@/app/_src/models/SongResponse";
2 import { TauriResponse } from "./shared";
3 +import { SongProviderVote } from "@/app/_src/models/SongVotesDetailResponse";
4
5 // Need to be renamed into more generic name
6 export interface ContentCarouselResponse {
@@ -18,4 +19,11 @@ export interface PlayerPrepareResponse {
19 status: TauriResponse,
20 message: string,
21 audio_file_name?: string,
22 +}
23 +
24 +export interface SongProviderResponse {
25 + status: TauriResponse,
26 + message: string,
27 + song_provider: SongProvider
28 + votes: SongProviderVote[]
29 }
\ No newline at end of file
frontend/splitfire-desktop/src-tauri/src/models/content.rs
+3 -3
@@ -39,8 +39,8 @@ pub enum ProviderType {
39
40 #[derive(Serialize)]
41 #[derive(Debug)]
42 -pub struct ContentSongBridgeResponse {
43 - pub code: TauriResponse,
42 +pub struct ContentSongProviderResponse {
43 + pub status: TauriResponse,
44 pub message: String,
45 pub song_provider: Option<SongProvider>,
46 pub votes: Vec<SongProviderVote>
@@ -48,7 +48,7 @@ pub struct ContentSongBridgeResponse {
48
49 #[derive(Serialize, Deserialize)]
50 #[derive(Debug)]
51 -pub struct SongBridgeResponse {
51 +pub struct SongProviderResponse {
52 pub code: i32, // API response code
53 pub message: String,
54 pub error: Option<String>,
frontend/splitfire-desktop/src-tauri/src/rest/content.rs
+28 -22
@@ -5,8 +5,8 @@ use crate::{
5 },
6 models::{
7 content::{
8 - CarouselResponse, ContentCarouselResponse, ContentSongBridgeResponse,
9 - SongBridgeResponse, VoteType,
8 + CarouselResponse, ContentCarouselResponse, ContentSongProviderResponse,
9 + SongProviderResponse, VoteType,
10 },
11 player::TauriResponse,
12 },
@@ -91,7 +91,10 @@ pub async fn content_ready_to_play() -> ContentCarouselResponse {
91 }
92
93 #[tauri::command]
94 -pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSongBridgeResponse {
94 +pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSongProviderResponse {
95 + // song_provider_id is a string because it is comes from a nextjs query parameter.
96 + // When we get it from the server, it actually is a number.
97 + // It is Rails id convention.
98 debug!("Song provider id: {:?}", song_provider_id);
99 let url =
100 content_url_builder(PATH_SONG_BRIDGE_DETAIL).replace("{providerId}", &song_provider_id);
@@ -101,8 +104,8 @@ pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSong
104 Ok(response) => response,
105 Err(e) => {
106 error!("Failed to get response: {:?}", e);
104 - return ContentSongBridgeResponse {
105 - code: TauriResponse::Error,
107 + return ContentSongProviderResponse {
108 + status: TauriResponse::Error,
109 message: e.to_string(),
110 song_provider: None,
111 votes: vec![],
@@ -110,12 +113,12 @@ pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSong
113 }
114 };
115
113 - let res: SongBridgeResponse = match response.json().await {
116 + let res: SongProviderResponse = match response.json().await {
117 Ok(json) => json,
118 Err(e) => {
119 error!("Failed to parse response: {:?}", e);
117 - return ContentSongBridgeResponse {
118 - code: TauriResponse::Error,
120 + return ContentSongProviderResponse {
121 + status: TauriResponse::Error,
122 message: e.to_string(),
123 song_provider: None,
124 votes: vec![],
@@ -130,8 +133,8 @@ pub async fn content_song_bridge_detail(song_provider_id: String) -> ContentSong
133 None => vec![],
134 };
135
133 - ContentSongBridgeResponse {
134 - code: TauriResponse::Success,
136 + ContentSongProviderResponse {
137 + status: TauriResponse::Success,
138 message: res.message,
139 song_provider: res.song_provider,
140 votes,
@@ -177,16 +180,19 @@ pub async fn content_top_voted() -> ContentCarouselResponse {
180
181 #[tauri::command]
182 pub async fn content_song_bridge_vote(
180 - song_provider_id: String,
183 + song_provider_id: i32,
184 vote_type: VoteType,
185 access_token: String,
183 -) -> ContentSongBridgeResponse {
186 +) -> ContentSongProviderResponse {
187 debug!("Song provider id: {:?}", song_provider_id);
185 - let url = content_url_builder(PATH_SONG_BRIDGE_VOTE).replace("{providerId}", &song_provider_id);
186 - let body = json!({ "vote_type": vote_type, "provider_id": song_provider_id }).to_string();
188 + let url = content_url_builder(PATH_SONG_BRIDGE_VOTE).replace("{providerId}", &song_provider_id.to_string());
189 + let body = json!({
190 + "vote_type": vote_type,
191 + "provider_id": song_provider_id
192 + });
193 let response: Result<reqwest::Response, reqwest::Error> = Client::new()
194 .post(url)
189 - .body(body)
195 + .json(&body)
196 .header("Authorization", format!("Bearer {}", access_token))
197 .send()
198 .await;
@@ -195,8 +201,8 @@ pub async fn content_song_bridge_vote(
201 Ok(response) => response,
202 Err(e) => {
203 error!("Failed to get response: {:?}", e);
198 - return ContentSongBridgeResponse {
199 - code: TauriResponse::Error,
204 + return ContentSongProviderResponse {
205 + status: TauriResponse::Error,
206 message: e.to_string(),
207 song_provider: None,
208 votes: vec![],
@@ -204,12 +210,12 @@ pub async fn content_song_bridge_vote(
210 }
211 };
212
207 - let res: SongBridgeResponse = match response.json().await {
213 + let res: SongProviderResponse = match response.json().await {
214 Ok(json) => json,
215 Err(e) => {
216 error!("Failed to parse response: {:?}", e);
211 - return ContentSongBridgeResponse {
212 - code: TauriResponse::Error,
217 + return ContentSongProviderResponse {
218 + status: TauriResponse::Error,
219 message: e.to_string(),
220 song_provider: None,
221 votes: vec![],
@@ -224,8 +230,8 @@ pub async fn content_song_bridge_vote(
230 None => vec![],
231 };
232
227 - ContentSongBridgeResponse {
228 - code: TauriResponse::Success,
233 + ContentSongProviderResponse {
234 + status: TauriResponse::Success,
235 message: res.message,
236 song_provider: res.song_provider,
237 votes,