diff --git a/src/components/analytics/exif/AlbumPhotosChart.tsx b/src/components/analytics/exif/AlbumPhotosChart.tsx new file mode 100644 index 0000000..08ffca6 --- /dev/null +++ b/src/components/analytics/exif/AlbumPhotosChart.tsx @@ -0,0 +1,39 @@ +import { Card } from "@/components/ui/card"; +import PieChart, { IPieChartData } from "@/components/ui/pie-chart"; +import { getAlbumPhotosStatistics } from "@/handlers/api/analytics.handler"; +import React, { useEffect, useState } from "react"; + +export default function AlbumPhotosChart() { + const [chartData, setChartData] = useState([]); + const [loading, setLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); + + const fetchData = async () => { + setLoading(true); + try { + const data = await getAlbumPhotosStatistics(); + setChartData(data); + } catch (error: any) { + setErrorMessage(error?.message || "Failed to fetch album photos data"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, []); + + return ( + + + + ); +} diff --git a/src/components/analytics/exif/GeoPhotosChart.tsx b/src/components/analytics/exif/GeoPhotosChart.tsx new file mode 100644 index 0000000..5d7f15f --- /dev/null +++ b/src/components/analytics/exif/GeoPhotosChart.tsx @@ -0,0 +1,39 @@ +import { Card } from "@/components/ui/card"; +import PieChart, { IPieChartData } from "@/components/ui/pie-chart"; +import { getGeoPhotosStatistics } from "@/handlers/api/analytics.handler"; +import React, { useEffect, useState } from "react"; + +export default function GeoPhotosChart() { + const [chartData, setChartData] = useState([]); + const [loading, setLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); + + const fetchData = async () => { + setLoading(true); + try { + const data = await getGeoPhotosStatistics(); + setChartData(data); + } catch (error: any) { + setErrorMessage(error?.message || "Failed to fetch geo photos data"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, []); + + return ( + + + + ); +} diff --git a/src/components/analytics/exif/PeopleNamesChart.tsx b/src/components/analytics/exif/PeopleNamesChart.tsx new file mode 100644 index 0000000..e90d9bf --- /dev/null +++ b/src/components/analytics/exif/PeopleNamesChart.tsx @@ -0,0 +1,39 @@ +import { Card } from "@/components/ui/card"; +import PieChart, { IPieChartData } from "@/components/ui/pie-chart"; +import { getPeopleNamesStatistics } from "@/handlers/api/analytics.handler"; +import React, { useEffect, useState } from "react"; + +export default function PeopleNamesChart() { + const [chartData, setChartData] = useState([]); + const [loading, setLoading] = useState(false); + const [errorMessage, setErrorMessage] = useState(null); + + const fetchData = async () => { + setLoading(true); + try { + const data = await getPeopleNamesStatistics(); + setChartData(data); + } catch (error: any) { + setErrorMessage(error?.message || "Failed to fetch people names data"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchData(); + }, []); + + return ( + + + + ); +} diff --git a/src/config/routes.ts b/src/config/routes.ts index b58dfef..bf04144 100644 --- a/src/config/routes.ts +++ b/src/config/routes.ts @@ -59,6 +59,9 @@ export const SEARCH_PLACES_PATH = BASE_PROXY_ENDPOINT + "/search/places"; export const ASSET_STATISTICS = BASE_PROXY_ENDPOINT + "/assets/statistics"; export const LIVE_PHOTO_STATISTICS = BASE_API_ENDPOINT + "/analytics/statistics/livephoto"; export const HEATMAP_DATA = BASE_API_ENDPOINT + "/analytics/statistics/heatmap"; +export const PEOPLE_NAMES_STATISTICS = BASE_API_ENDPOINT + "/analytics/statistics/people-names"; +export const GEO_PHOTOS_STATISTICS = BASE_API_ENDPOINT + "/analytics/statistics/geo-photos"; +export const ALBUM_PHOTOS_STATISTICS = BASE_API_ENDPOINT + "/analytics/statistics/album-photos"; // Common export const GET_FILTERS = BASE_API_ENDPOINT + "/filters/asset-filters"; diff --git a/src/handlers/api/analytics.handler.ts b/src/handlers/api/analytics.handler.ts index 6649906..605792e 100644 --- a/src/handlers/api/analytics.handler.ts +++ b/src/handlers/api/analytics.handler.ts @@ -1,4 +1,4 @@ -import { ASSET_STATISTICS, EXIF_DISTRIBUTION_PATH, HEATMAP_DATA, LIVE_PHOTO_STATISTICS } from "@/config/routes"; +import { ASSET_STATISTICS, EXIF_DISTRIBUTION_PATH, HEATMAP_DATA, LIVE_PHOTO_STATISTICS, PEOPLE_NAMES_STATISTICS, GEO_PHOTOS_STATISTICS, ALBUM_PHOTOS_STATISTICS } from "@/config/routes"; import API from "@/lib/api"; export type ISupportedEXIFColumns = @@ -18,4 +18,16 @@ export const getLivePhotoStatistics = async () => { export const getHeatMapData = async () => { return API.get(HEATMAP_DATA); +} + +export const getPeopleNamesStatistics = async () => { + return API.get(PEOPLE_NAMES_STATISTICS); +} + +export const getGeoPhotosStatistics = async () => { + return API.get(GEO_PHOTOS_STATISTICS); +} + +export const getAlbumPhotosStatistics = async () => { + return API.get(ALBUM_PHOTOS_STATISTICS); } \ No newline at end of file diff --git a/src/handlers/api/asset.handler.ts b/src/handlers/api/asset.handler.ts index 85667a5..31f3101 100644 --- a/src/handlers/api/asset.handler.ts +++ b/src/handlers/api/asset.handler.ts @@ -72,7 +72,7 @@ export const getAssetGeoHeatmap = async (filters: IHeatMapParams) => { return API.get(ASSET_GEO_HEATMAP_PATH, filters); } -export const deleteAssets = async (ids: string[]) => { +export const deleteAssets = async (ids: string[], options: { force?: boolean } = { force: true }) => { return API.delete(UPDATE_ASSETS_PATH, { ids, force: true }); } diff --git a/src/pages/analytics/exif.tsx b/src/pages/analytics/exif.tsx index 23da1c4..edc9073 100644 --- a/src/pages/analytics/exif.tsx +++ b/src/pages/analytics/exif.tsx @@ -11,6 +11,9 @@ import { CardTitle, } from "@/components/ui/card"; import AssetHeatMap from "@/components/analytics/exif/AssetHeatMap"; +import PeopleNamesChart from "@/components/analytics/exif/PeopleNamesChart"; +import GeoPhotosChart from "@/components/analytics/exif/GeoPhotosChart"; +import AlbumPhotosChart from "@/components/analytics/exif/AlbumPhotosChart"; import { useEffect, useState } from "react"; import { getAssetStatistics, getLivePhotoStatistics } from "@/handlers/api/analytics.handler"; import { humanizeBytes } from "@/helpers/string.helper"; @@ -130,6 +133,14 @@ export default function ExifDataAnalytics() { + + {/* New Analytics Charts */} +
+ + + +
+
{exifCharts.map((chart) => ( { - return deleteAssets(contextState.selectedIds).then(() => { + const handleDelete = (force?: boolean) => { + return deleteAssets(contextState.selectedIds, { force }).then(() => { const newAssets = contextState.assets.filter((a) => !contextState.selectedIds.includes(a.id)); setAssets(newAssets) contextState.updateContext({ @@ -264,7 +264,7 @@ export default function EmptyVideosPage() { handleDelete(true)} disabled={contextState.selectedIds.length === 0} >