Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localized date #377

Merged
merged 4 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,11 @@ You can follow the instructions [here](https://github.com/Yooooomi/your_spotify/
| MONGO_ENDPOINT | mongodb://mongo:27017/your_spotify | The endpoint of the Mongo database, where **mongo** is the name of your service in the compose file |
| LOG_LEVEL | info | The log level, debug is useful if you encouter any bugs |
| CORS | _not defined_ | List of comma-separated origin allowed |
| COOKIE_VALIDITY_MS | 1h | Validity time of the authentication cookie, following [this pattern](https://github.com/vercel/ms) |
| COOKIE_VALIDITY_MS | 1h | Validity time of the authentication cookie, following [this pattern](https://github.com/vercel/ms) |
| MAX_IMPORT_CACHE_SIZE | Infinite | The maximum element in the cache when importing data from an outside source, more cache means less requests to Spotify, resulting in faster imports |
| MONGO_NO_ADMIN_RIGHTS | false | Do not ask for admin right on the Mongo database |
| PORT | 8080 | The port of the server, **do not** modify if you're using docker |
| FRAME_ANCESTORS | _not defined_ | Sites allowed to frame the website, comma separated list of URLs (`i-want-a-security-vulnerability-and-want-to-allow-all-frame-ancestors` to allow every website) |

## CORS

Expand Down
5 changes: 3 additions & 2 deletions apps/client/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "@your_spotify/client",
"version": "1.9.1",
"version": "1.10.0",
"private": true,
"scripts": {
"start": "DISABLE_ESLINT_PLUGIN=true react-scripts start",
"build": "DISABLE_ESLINT_PLUGIN=true react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/ --ext .tsx,.ts"
"lint": "eslint src/ --ext .tsx,.ts",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@emotion/react": "11.11.4",
Expand Down
2 changes: 1 addition & 1 deletion apps/client/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

Restricting connect-src is done at start of the client server.
-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' https://i.scdn.co; connect-src http://localhost:8080;" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; object-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' https://i.scdn.co; connect-src 'self' http://localhost:8080/;" />

<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
Expand Down
15 changes: 15 additions & 0 deletions apps/client/scripts/run/variables.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,18 @@ then
fi

sed -i "s#connect-src \(.*\);#connect-src 'self' $CSP_CONNECT_SRC;#g" "$VAR_PATH/index.html"

# Handling frame-ancestors preferences
SERVE_CONFIG_PATH="/app/apps/client/scripts/run/serve.json"

if [[ -z "$FRAME_ANCESTORS" ]]
then
FRAME_ANCESTORS="'none'"
elif [[ "$FRAME_ANCESTORS" == "i-want-a-security-vulnerability-and-want-to-allow-all-frame-ancestors" ]]
then
FRAME_ANCESTORS="*"
else
FRAME_ANCESTORS=${FRAME_ANCESTORS//,/ }
fi

sed -i "s#frame-ancestors \(.*\);#frame-ancestors $FRAME_ANCESTORS;#g" "$SERVE_CONFIG_PATH"
2 changes: 1 addition & 1 deletion apps/client/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setDataInterval } from "../../services/redux/modules/user/reducer";
import { selectIntervalDetail } from "../../services/redux/modules/user/selector";
import { intervalDetailToRedux } from "../../services/redux/modules/user/utils";
import { useAppDispatch } from "../../services/redux/tools";
import IntervalSelector from "../IntervalSelector";
import { IntervalSelector } from "../IntervalSelector";
import Text from "../Text";
import { LayoutContext } from "../Layout/LayoutContext";
import { useSider } from "../Layout/useSider";
Expand Down
34 changes: 16 additions & 18 deletions apps/client/src/components/History/Track/Track.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { Fragment, useMemo } from "react";
import clsx from "clsx";
import {
dateToListenedAt,
msToMinutesAndSeconds,
} from '../../../services/stats';
import { Album, Artist, Track as TrackType } from '../../../services/types';
import s from './index.module.css';
import InlineArtist from '../../InlineArtist';
import Text from '../../Text';
import TrackOptions from '../../TrackOptions';
import InlineTrack from '../../InlineTrack';
import { ColumnDescription, GridRowWrapper } from '../../Grid';
import PlayButton from '../../PlayButton';
import { useMobile } from '../../../services/hooks/hooks';
import { trackGrid } from './TrackGrid';
import LongClickableTrack from '../../LongClickableTrack';
import InlineAlbum from '../../InlineAlbum';
import { msToMinutesAndSeconds } from "../../../services/stats";
import { Album, Artist, Track as TrackType } from "../../../services/types";
import InlineArtist from "../../InlineArtist";
import Text from "../../Text";
import TrackOptions from "../../TrackOptions";
import InlineTrack from "../../InlineTrack";
import { ColumnDescription, GridRowWrapper } from "../../Grid";
import PlayButton from "../../PlayButton";
import { useMobile } from "../../../services/hooks/hooks";
import LongClickableTrack from "../../LongClickableTrack";
import InlineAlbum from "../../InlineAlbum";
import { DateFormatter } from "../../../services/date";
import { trackGrid } from "./TrackGrid";
import s from "./index.module.css";

interface TrackProps {
listenedAt?: Date;
Expand Down Expand Up @@ -67,15 +65,15 @@ export default function Track({
{
...trackGrid.listened,
node: listenedAt && !isMobile && (
<Text>{dateToListenedAt(listenedAt)}</Text>
<Text>{DateFormatter.listenedAt(listenedAt)}</Text>
),
},
{
...trackGrid.option,
node: !isMobile && <TrackOptions track={track} />,
},
],
[album.images, album.name, artists, isMobile, isTablet, listenedAt, track],
[album, artists, isMobile, isTablet, listenedAt, track],
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Tooltip from "../../Tooltip";
import { TitleFormatter, ValueFormatter } from "../../Tooltip/Tooltip";
import LoadingImplementedChart from "../LoadingImplementedChart";
import { ImplementedChartProps } from "../types";
import { DateFormatter } from "../../../services/date";

interface BestOfHourProps extends ImplementedChartProps {}

Expand Down Expand Up @@ -61,10 +62,6 @@ function getElementData(
);
}

function formatX(value: any) {
return `${value}:00`;
}

export default function BestOfHour({ className }: BestOfHourProps) {
const { interval } = useSelector(selectRawIntervalDetail);
const [element, setElement] = useState<Element>(Element.ARTIST);
Expand All @@ -80,7 +77,8 @@ export default function BestOfHour({ className }: BestOfHourProps) {
}, [result]);

const tooltipTitle = useCallback<TitleFormatter<typeof data>>(
({ x }) => `20 most listened ${element} at ${x}:00`,
({ x }) =>
`20 most listened ${element} at ${DateFormatter.fromNumberToHour(x)}`,
[element],
);

Expand Down Expand Up @@ -130,7 +128,7 @@ export default function BestOfHour({ className }: BestOfHourProps) {
className={className}>
<StackedBar
data={data}
xFormat={formatX}
xFormat={DateFormatter.fromNumberToHour}
customTooltip={<Tooltip title={tooltipTitle} value={tooltipValue} />}
/>
</ChartCard>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo } from "react";
import { useCallback, useMemo } from "react";
import { useSelector } from "react-redux";
import { api } from "../../../services/apis/api";
import { useAPI } from "../../../services/hooks/hooks";
Expand All @@ -9,14 +9,14 @@ import LoadingImplementedChart from "../LoadingImplementedChart";
import { selectRawIntervalDetail } from "../../../services/redux/modules/user/selector";
import Tooltip from "../../Tooltip";
import { TitleFormatter, ValueFormatter } from "../../Tooltip/Tooltip";
import { DateFormatter } from "../../../services/date";

interface ListeningRepartitionProps extends ImplementedChartProps {}

const formatXAxis = (value: any) => `${value}:00`;

const formatYAxis = (value: any) => `${value}%`;

const tooltipTitle: TitleFormatter<unknown[]> = ({ x }) => `${x}:00`;
const tooltipTitle: TitleFormatter<unknown[]> = ({ x }) =>
DateFormatter.fromNumberToHour(x);

export default function ListeningRepartition({
className,
Expand Down Expand Up @@ -72,7 +72,7 @@ export default function ListeningRepartition({
<ChartCard className={className} title="Listening distribution over day">
<Bar
data={data}
xFormat={formatXAxis}
xFormat={DateFormatter.fromNumberToHour}
yFormat={formatYAxis}
customTooltip={<Tooltip title={tooltipTitle} value={tooltipValue} />}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ import {
Select,
} from "@mui/material";
import React, { useState, useCallback, useMemo } from "react";
import {
startOfDay,
getAppropriateTimesplitFromRange,
endOfDay,
} from "../../services/date";
import { endOfDay, startOfDay } from "date-fns";
import { getAppropriateTimesplitFromRange } from "../../services/date";
import { useMobile } from "../../services/hooks/hooks";
import {
allIntervals,
Expand All @@ -34,7 +31,7 @@ interface IntervalSelectorProps {
forceTiny?: boolean;
}

export default function IntervalSelector({
export function IntervalSelector({
value,
onChange,
selectType,
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/components/IntervalSelector/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from "./IntervalSelector";
export * from "./IntervalSelector";
21 changes: 10 additions & 11 deletions apps/client/src/scenes/AlbumStats/AlbumRank/AlbumRank.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { CircularProgress } from '@mui/material';
import clsx from 'clsx';
import { useCallback, useMemo } from 'react';
import InlineAlbum from '../../../components/InlineAlbum';
import Text from '../../../components/Text';
import { api } from '../../../services/apis/api';
import { useLoadAlbums } from '../../../services/hooks/artist';
import { useAPI } from '../../../services/hooks/hooks';
import s from './index.module.css';
import { CircularProgress } from "@mui/material";
import clsx from "clsx";
import { useCallback, useMemo } from "react";
import InlineAlbum from "../../../components/InlineAlbum";
import Text from "../../../components/Text";
import { api } from "../../../services/apis/api";
import { useLoadAlbums } from "../../../services/hooks/artist";
import { useAPI } from "../../../services/hooks/hooks";
import s from "./index.module.css";

interface AlbumRankProps {
albumId: string;
Expand All @@ -22,7 +22,6 @@ export default function AlbumRank({ albumId }: AlbumRankProps) {
const { albums, loaded } = useLoadAlbums(ids);

const getArtist = useCallback((id: string) => albums[id], [albums]);
console.log(albumRank, loaded);
if (!albumRank || !loaded) {
return (
<div className={s.loading}>
Expand Down Expand Up @@ -53,7 +52,7 @@ export default function AlbumRank({ albumId }: AlbumRankProps) {
{albumRank.index +
k +
(albumRank.isMax ? 1 : 0) +
(albumRank.isMin ? -1 : 0)}{' '}
(albumRank.isMin ? -1 : 0)}{" "}
<InlineAlbum album={getArtist(rank.id)!} noStyle />
</div>
))}
Expand Down
30 changes: 15 additions & 15 deletions apps/client/src/scenes/AlbumStats/AlbumStats.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { CircularProgress, Grid } from '@mui/material';
import { TimelapseOutlined } from '@mui/icons-material';
import Header from '../../components/Header';
import { AlbumStatsResponse } from '../../services/apis/api';
import s from './index.module.css';
import InlineArtist from '../../components/InlineArtist';
import IdealImage from '../../components/IdealImage';
import FirstAndLast from '../ArtistStats/FirstAndLast';
import InlineTrack from '../../components/InlineTrack';
import TitleCard from '../../components/TitleCard';
import Text from '../../components/Text';
import ImageTwoLines from '../../components/ImageTwoLines';
import { msToMinutesAndSeconds } from '../../services/stats';
import AlbumRank from './AlbumRank';
import { CircularProgress, Grid } from "@mui/material";
import { TimelapseOutlined } from "@mui/icons-material";
import Header from "../../components/Header";
import { AlbumStatsResponse } from "../../services/apis/api";
import InlineArtist from "../../components/InlineArtist";
import IdealImage from "../../components/IdealImage";
import FirstAndLast from "../ArtistStats/FirstAndLast";
import InlineTrack from "../../components/InlineTrack";
import TitleCard from "../../components/TitleCard";
import Text from "../../components/Text";
import ImageTwoLines from "../../components/ImageTwoLines";
import { msToMinutesAndSeconds } from "../../services/stats";
import s from "./index.module.css";
import AlbumRank from "./AlbumRank";

interface AlbumStatsProps {
stats: AlbumStatsResponse;
Expand All @@ -37,7 +37,7 @@ export default function AlbumStats({ stats }: AlbumStatsProps) {
subtitle={stats.artists.map((artist, k) => (
<>
<InlineArtist artist={artist} key={artist.id} />
{k < stats.artists.length - 1 && ', '}
{k < stats.artists.length - 1 && ", "}
</>
))}
hideInterval
Expand Down
41 changes: 22 additions & 19 deletions apps/client/src/scenes/ArtistStats/ArtistStats.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { CircularProgress, Grid } from '@mui/material';
import { useSelector } from 'react-redux';
import Header from '../../components/Header';
import TitleCard from '../../components/TitleCard';
import { ArtistStatsResponse } from '../../services/apis/api';
import { buildFromDateId, dateToMonthAndYear } from '../../services/stats';
import s from './index.module.css';
import DayRepartition from './DayRepartition';
import Text from '../../components/Text';
import ArtistRank from './ArtistRank/ArtistRank';
import InlineTrack from '../../components/InlineTrack';
import FirstAndLast from './FirstAndLast';
import ArtistContextMenu from './ArtistContextMenu';
import { selectBlacklistedArtist } from '../../services/redux/modules/user/selector';
import IdealImage from '../../components/IdealImage';
import ImageTwoLines from '../../components/ImageTwoLines';
import InlineAlbum from '../../components/InlineAlbum';
import { CircularProgress, Grid } from "@mui/material";
import { useSelector } from "react-redux";
import Header from "../../components/Header";
import TitleCard from "../../components/TitleCard";
import { ArtistStatsResponse } from "../../services/apis/api";
import { buildFromDateId } from "../../services/stats";
import Text from "../../components/Text";
import InlineTrack from "../../components/InlineTrack";
import { selectBlacklistedArtist } from "../../services/redux/modules/user/selector";
import IdealImage from "../../components/IdealImage";
import ImageTwoLines from "../../components/ImageTwoLines";
import InlineAlbum from "../../components/InlineAlbum";
import { DateFormatter } from "../../services/date";
import ArtistContextMenu from "./ArtistContextMenu";
import FirstAndLast from "./FirstAndLast";
import ArtistRank from "./ArtistRank/ArtistRank";
import DayRepartition from "./DayRepartition";
import s from "./index.module.css";

interface ArtistStatsProps {
artistId: string;
Expand Down Expand Up @@ -95,7 +96,9 @@ export default function ArtistStats({ artistId, stats }: ArtistStatsProps) {
{bestPeriod && (
<div className={s.bestperiod}>
<Text element="strong">
{dateToMonthAndYear(buildFromDateId(bestPeriod._id))}
{DateFormatter.toMonthStringYear(
buildFromDateId(bestPeriod._id),
)}
</Text>
<Text>
{bestPeriod.count} times (
Expand All @@ -107,7 +110,7 @@ export default function ArtistStats({ artistId, stats }: ArtistStatsProps) {
{secondBestPeriod && (
<div className={s.bestperiod}>
<Text element="strong">
{dateToMonthAndYear(
{DateFormatter.toMonthStringYear(
buildFromDateId(secondBestPeriod._id),
)}
</Text>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ReactNode } from "react";
import { dateToListenedAt } from "../../../services/stats";
import { SpotifyImage } from "../../../services/types";
import TitleCard from "../../../components/TitleCard";
import IdealImage from "../../../components/IdealImage";
import ImageTwoLines from "../../../components/ImageTwoLines";
import { DateFormatter } from "../../../services/date";
import s from "./index.module.css";

interface FirstAndLastProps {
Expand Down Expand Up @@ -36,7 +36,7 @@ export default function FirstAndLast({
/>
}
first={lastElement}
second={`Last listened on ${dateToListenedAt(new Date(lastDate))}`}
second={`Last listened on ${DateFormatter.listenedAt(new Date(lastDate))}`}
/>
</div>
<div className={s.item}>
Expand All @@ -50,7 +50,7 @@ export default function FirstAndLast({
/>
}
first={firstElement}
second={`First listened on ${dateToListenedAt(new Date(firstDate))}`}
second={`First listened on ${DateFormatter.listenedAt(new Date(firstDate))}`}
/>
</div>
</TitleCard>
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/scenes/Collaborative/Affinity/Affinity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AdminAccount } from "../../../services/redux/modules/admin/reducer";
import { selectAccounts } from "../../../services/redux/modules/admin/selector";
import { CollaborativeMode } from "../../../services/types";
import { selectUser } from "../../../services/redux/modules/user/selector";
import IntervalSelector from "../../../components/IntervalSelector";
import { IntervalSelector } from "../../../components/IntervalSelector";
import Text from "../../../components/Text";
import {
detailIntervalToQuery,
Expand Down
Loading