Skip to content

Commit

Permalink
Merge pull request #377 from Yooooomi/feature/localized-date
Browse files Browse the repository at this point in the history
Localized date
  • Loading branch information
Yooooomi authored Mar 23, 2024
2 parents 15102e4 + 1e02375 commit b5a3517
Show file tree
Hide file tree
Showing 41 changed files with 542 additions and 232 deletions.
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

0 comments on commit b5a3517

Please sign in to comment.