mirror of
https://github.com/apricote/Listory.git
synced 2026-02-06 17:57:03 +00:00
refator: use TimeOptions for TopArtists report
This commit is contained in:
parent
ad0d197105
commit
5bc76f23d0
9 changed files with 62 additions and 46 deletions
|
|
@ -111,7 +111,9 @@ export const getListensReport = async (
|
||||||
export const getTopArtists = async (
|
export const getTopArtists = async (
|
||||||
options: TopArtistsOptions
|
options: TopArtistsOptions
|
||||||
): Promise<TopArtistsItem[]> => {
|
): Promise<TopArtistsItem[]> => {
|
||||||
const { timePreset, customTimeStart, customTimeEnd } = options;
|
const {
|
||||||
|
time: { timePreset, customTimeStart, customTimeEnd },
|
||||||
|
} = options;
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`/api/v1/reports/top-artists?${qs({
|
`/api/v1/reports/top-artists?${qs({
|
||||||
|
|
|
||||||
7
frontend/src/api/entities/time-options.ts
Normal file
7
frontend/src/api/entities/time-options.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { TimePreset } from "./time-preset.enum";
|
||||||
|
|
||||||
|
export interface TimeOptions {
|
||||||
|
timePreset: TimePreset;
|
||||||
|
customTimeStart: Date;
|
||||||
|
customTimeEnd: Date;
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { TimePreset } from "./time-preset.enum";
|
import { TimePreset } from "./time-preset.enum";
|
||||||
|
import { TimeOptions } from "./time-options";
|
||||||
|
|
||||||
export interface TopArtistsOptions {
|
export interface TopArtistsOptions {
|
||||||
timePreset: TimePreset;
|
time: TimeOptions;
|
||||||
customTimeStart: Date;
|
|
||||||
customTimeEnd: Date;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { TimeOptions } from "../api/entities/time-options";
|
||||||
import { TimePreset } from "../api/entities/time-preset.enum";
|
import { TimePreset } from "../api/entities/time-preset.enum";
|
||||||
import { TopArtistsOptions } from "../api/entities/top-artists-options";
|
|
||||||
import { DateSelect } from "./inputs/DateSelect";
|
import { DateSelect } from "./inputs/DateSelect";
|
||||||
|
|
||||||
interface ReportOptionsProps {
|
interface ReportTimeOptionsProps {
|
||||||
reportOptions: TopArtistsOptions;
|
timeOptions: TimeOptions;
|
||||||
setReportOptions: (options: TopArtistsOptions) => void;
|
setTimeOptions: (options: TimeOptions) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timePresetOptions = [
|
const timePresetOptions = [
|
||||||
|
|
@ -18,9 +18,9 @@ const timePresetOptions = [
|
||||||
{ value: TimePreset.CUSTOM, description: "Custom" },
|
{ value: TimePreset.CUSTOM, description: "Custom" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ReportOptions: React.FC<ReportOptionsProps> = ({
|
export const ReportTimeOptions: React.FC<ReportTimeOptionsProps> = ({
|
||||||
reportOptions,
|
timeOptions,
|
||||||
setReportOptions,
|
setTimeOptions,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="md:flex">
|
<div className="md:flex">
|
||||||
|
|
@ -29,33 +29,37 @@ export const ReportOptions: React.FC<ReportOptionsProps> = ({
|
||||||
<select
|
<select
|
||||||
className="block appearance-none min-w-full md:w-1/4 bg-white border border-gray-400 hover:border-gray-500 p-2 rounded shadow leading-tight focus:outline-none focus:shadow-outline"
|
className="block appearance-none min-w-full md:w-1/4 bg-white border border-gray-400 hover:border-gray-500 p-2 rounded shadow leading-tight focus:outline-none focus:shadow-outline"
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setReportOptions({
|
setTimeOptions({
|
||||||
...reportOptions,
|
...timeOptions,
|
||||||
timePreset: e.target.value as TimePreset,
|
timePreset: e.target.value as TimePreset,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{timePresetOptions.map(({ value, description }) => (
|
{timePresetOptions.map(({ value, description }) => (
|
||||||
<option value={value} key={value}>
|
<option
|
||||||
|
value={value}
|
||||||
|
key={value}
|
||||||
|
selected={value === timeOptions.timePreset}
|
||||||
|
>
|
||||||
{description}
|
{description}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{reportOptions.timePreset === TimePreset.CUSTOM && (
|
{timeOptions.timePreset === TimePreset.CUSTOM && (
|
||||||
<div className="md:flex text-gray-700">
|
<div className="md:flex text-gray-700">
|
||||||
<DateSelect
|
<DateSelect
|
||||||
label="Start"
|
label="Start"
|
||||||
value={reportOptions.customTimeStart}
|
value={timeOptions.customTimeStart}
|
||||||
onChange={(newDate) =>
|
onChange={(newDate) =>
|
||||||
setReportOptions({ ...reportOptions, customTimeStart: newDate })
|
setTimeOptions({ ...timeOptions, customTimeStart: newDate })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<DateSelect
|
<DateSelect
|
||||||
label="End"
|
label="End"
|
||||||
value={reportOptions.customTimeEnd}
|
value={timeOptions.customTimeEnd}
|
||||||
onChange={(newDate) =>
|
onChange={(newDate) =>
|
||||||
setReportOptions({ ...reportOptions, customTimeEnd: newDate })
|
setTimeOptions({ ...timeOptions, customTimeEnd: newDate })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -5,19 +5,20 @@ import { TimePreset } from "../api/entities/time-preset.enum";
|
||||||
import { TopArtistsOptions } from "../api/entities/top-artists-options";
|
import { TopArtistsOptions } from "../api/entities/top-artists-options";
|
||||||
import { useAsync } from "../hooks/use-async";
|
import { useAsync } from "../hooks/use-async";
|
||||||
import { useAuth } from "../hooks/use-auth";
|
import { useAuth } from "../hooks/use-auth";
|
||||||
import { ReportOptions } from "./ReportOptions";
|
import { ReportTimeOptions } from "./ReportTimeOptions";
|
||||||
|
import { TimeOptions } from "../api/entities/time-options";
|
||||||
|
|
||||||
export const ReportTopArtists: React.FC = () => {
|
export const ReportTopArtists: React.FC = () => {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
const [reportOptions, setReportOptions] = useState<TopArtistsOptions>({
|
const [timeOptions, setTimeOptions] = useState<TimeOptions>({
|
||||||
timePreset: TimePreset.LAST_90_DAYS,
|
timePreset: TimePreset.LAST_90_DAYS,
|
||||||
customTimeStart: new Date(0),
|
customTimeStart: new Date(0),
|
||||||
customTimeEnd: new Date(),
|
customTimeEnd: new Date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchData = useMemo(() => () => getTopArtists(reportOptions), [
|
const fetchData = useMemo(() => () => getTopArtists({ time: timeOptions }), [
|
||||||
reportOptions,
|
timeOptions,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const { value: report, pending: isLoading } = useAsync(fetchData, []);
|
const { value: report, pending: isLoading } = useAsync(fetchData, []);
|
||||||
|
|
@ -35,9 +36,9 @@ export const ReportTopArtists: React.FC = () => {
|
||||||
<p className="text-2xl font-normal text-gray-700">Top Artists</p>
|
<p className="text-2xl font-normal text-gray-700">Top Artists</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="shadow-xl bg-gray-100 rounded p-5 m-2">
|
<div className="shadow-xl bg-gray-100 rounded p-5 m-2">
|
||||||
<ReportOptions
|
<ReportTimeOptions
|
||||||
reportOptions={reportOptions}
|
timeOptions={timeOptions}
|
||||||
setReportOptions={setReportOptions}
|
setTimeOptions={setTimeOptions}
|
||||||
/>
|
/>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,10 @@
|
||||||
import { IsEnum, IsISO8601, ValidateIf } from "class-validator";
|
import { ValidateNested } from "class-validator";
|
||||||
import { User } from "../../users/user.entity";
|
import { User } from "../../users/user.entity";
|
||||||
import { TimePreset } from "../timePreset.enum";
|
import { ReportTimeDto } from "./report-time.dto";
|
||||||
|
|
||||||
export class GetTopArtistsReportDto {
|
export class GetTopArtistsReportDto {
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
@IsEnum(TimePreset)
|
@ValidateNested()
|
||||||
timePreset: TimePreset;
|
time: ReportTimeDto;
|
||||||
|
|
||||||
@ValidateIf((o) => o.timePreset === TimePreset.CUSTOM)
|
|
||||||
@IsISO8601()
|
|
||||||
customTimeStart: string;
|
|
||||||
|
|
||||||
@ValidateIf((o) => o.timePreset === TimePreset.CUSTOM)
|
|
||||||
@IsISO8601()
|
|
||||||
customTimeEnd: string;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
src/reports/dto/report-time.dto.ts
Normal file
15
src/reports/dto/report-time.dto.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { IsEnum, IsISO8601, ValidateIf } from "class-validator";
|
||||||
|
import { TimePreset } from "../timePreset.enum";
|
||||||
|
|
||||||
|
export class ReportTimeDto {
|
||||||
|
@IsEnum(TimePreset)
|
||||||
|
timePreset: TimePreset;
|
||||||
|
|
||||||
|
@ValidateIf((o) => o.timePreset === TimePreset.CUSTOM)
|
||||||
|
@IsISO8601()
|
||||||
|
customTimeStart: string;
|
||||||
|
|
||||||
|
@ValidateIf((o) => o.timePreset === TimePreset.CUSTOM)
|
||||||
|
@IsISO8601()
|
||||||
|
customTimeEnd: string;
|
||||||
|
}
|
||||||
|
|
@ -24,9 +24,9 @@ export class ReportsController {
|
||||||
@Get("top-artists")
|
@Get("top-artists")
|
||||||
@Auth()
|
@Auth()
|
||||||
async getTopArtists(
|
async getTopArtists(
|
||||||
@Query() options: Omit<GetTopArtistsReportDto, "user">,
|
@Query() time: ReportTimeDto,
|
||||||
@ReqUser() user: User
|
@ReqUser() user: User
|
||||||
): Promise<TopArtistsReportDto> {
|
): Promise<TopArtistsReportDto> {
|
||||||
return this.reportsService.getTopArtists({ ...options, user });
|
return this.reportsService.getTopArtists({ user, time });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,13 +100,9 @@ export class ReportsService {
|
||||||
async getTopArtists(
|
async getTopArtists(
|
||||||
options: GetTopArtistsReportDto
|
options: GetTopArtistsReportDto
|
||||||
): Promise<TopArtistsReportDto> {
|
): Promise<TopArtistsReportDto> {
|
||||||
const { user, timePreset, customTimeStart, customTimeEnd } = options;
|
const { user, time: timePreset } = options;
|
||||||
|
|
||||||
const interval = this.getIntervalFromPreset({
|
const interval = this.getIntervalFromPreset(timePreset);
|
||||||
timePreset,
|
|
||||||
customTimeStart,
|
|
||||||
customTimeEnd,
|
|
||||||
});
|
|
||||||
|
|
||||||
const getArtistsWithCountQB = this.listensService
|
const getArtistsWithCountQB = this.listensService
|
||||||
.getScopedQueryBuilder()
|
.getScopedQueryBuilder()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue