refator: use TimeOptions for TopArtists report

This commit is contained in:
Julian Tölle 2020-07-12 17:16:33 +02:00
parent ad0d197105
commit 5bc76f23d0
9 changed files with 62 additions and 46 deletions

View file

@ -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({

View file

@ -0,0 +1,7 @@
import { TimePreset } from "./time-preset.enum";
export interface TimeOptions {
timePreset: TimePreset;
customTimeStart: Date;
customTimeEnd: Date;
}

View file

@ -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;
} }

View file

@ -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>

View file

@ -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>

View file

@ -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;
} }

View 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;
}

View file

@ -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 });
} }
} }

View file

@ -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()