Yassine Mhirsi commited on
Commit
6c8fc4b
·
1 Parent(s): 5f83845

Add caching support for analysis data in AnalysisPage

Browse files

- Implemented caching utilities to store and retrieve analysis results using localStorage.
- Updated AnalysisPage to utilize cached data for improved loading performance and user experience.
- Added loading state indication for data refresh in the UI.
- Enhanced error handling to display errors only when no cached data is available.

src/app/pages/AnalysisPage.tsx CHANGED
@@ -1,5 +1,5 @@
1
  import React, { useMemo, useState, useEffect } from 'react';
2
- import { parseCsv, formatError } from '../utils/index.ts';
3
  import { CsvRow } from '../types/index.ts';
4
  import { AnalysisResult } from '../types/analysis.types.ts';
5
  import { analyzeArgumentsFromCsv, getAnalysisResults } from '../services/analysis.service.ts';
@@ -28,6 +28,7 @@ const AnalysisPage: React.FC = () => {
28
  // User's historical analysis data
29
  const [userAnalysisData, setUserAnalysisData] = useState<AnalysisResult[]>([]);
30
  const [isLoadingStats, setIsLoadingStats] = useState<boolean>(true);
 
31
  const [statsError, setStatsError] = useState<string | null>(null);
32
 
33
  const fileName = useMemo(
@@ -35,18 +36,35 @@ const AnalysisPage: React.FC = () => {
35
  [selectedFile]
36
  );
37
 
38
- // Fetch user's analysis data on mount
39
  useEffect(() => {
40
  const fetchUserAnalysis = async () => {
41
- setIsLoadingStats(true);
 
 
 
 
 
 
 
 
 
42
  setStatsError(null);
 
 
43
  try {
44
  const response = await getAnalysisResults(1000, 0);
45
  setUserAnalysisData(response.results);
 
 
46
  } catch (err) {
47
- setStatsError(formatError(err));
 
 
 
48
  } finally {
49
  setIsLoadingStats(false);
 
50
  }
51
  };
52
 
@@ -131,6 +149,8 @@ const AnalysisPage: React.FC = () => {
131
  // Refresh user analysis data after successful analysis
132
  const updatedResponse = await getAnalysisResults(1000, 0);
133
  setUserAnalysisData(updatedResponse.results);
 
 
134
  } catch (err) {
135
  setError(formatError(err));
136
  } finally {
@@ -144,12 +164,22 @@ const AnalysisPage: React.FC = () => {
144
  {/* Statistics Section */}
145
  <div className="rounded-lg border border-slate-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 shadow-sm">
146
  <div className="border-b border-slate-200 dark:border-zinc-700 px-6 py-4">
147
- <h2 className="text-lg font-semibold text-slate-800 dark:text-white">
148
- Your Analysis Statistics
149
- </h2>
150
- <p className="text-sm text-slate-500 dark:text-zinc-400">
151
- Overview of all your analyzed arguments
152
- </p>
 
 
 
 
 
 
 
 
 
 
153
  </div>
154
 
155
  {isLoadingStats ? (
 
1
  import React, { useMemo, useState, useEffect } from 'react';
2
+ import { parseCsv, formatError, getCachedAnalysisData, cacheAnalysisData } from '../utils/index.ts';
3
  import { CsvRow } from '../types/index.ts';
4
  import { AnalysisResult } from '../types/analysis.types.ts';
5
  import { analyzeArgumentsFromCsv, getAnalysisResults } from '../services/analysis.service.ts';
 
28
  // User's historical analysis data
29
  const [userAnalysisData, setUserAnalysisData] = useState<AnalysisResult[]>([]);
30
  const [isLoadingStats, setIsLoadingStats] = useState<boolean>(true);
31
+ const [isRefreshingStats, setIsRefreshingStats] = useState<boolean>(false);
32
  const [statsError, setStatsError] = useState<string | null>(null);
33
 
34
  const fileName = useMemo(
 
36
  [selectedFile]
37
  );
38
 
39
+ // Fetch user's analysis data on mount with cache support
40
  useEffect(() => {
41
  const fetchUserAnalysis = async () => {
42
+ // Load cached data immediately
43
+ const cachedData = getCachedAnalysisData();
44
+ if (cachedData && cachedData.length > 0) {
45
+ setUserAnalysisData(cachedData);
46
+ setIsLoadingStats(false);
47
+ setIsRefreshingStats(true);
48
+ } else {
49
+ setIsLoadingStats(true);
50
+ }
51
+
52
  setStatsError(null);
53
+
54
+ // Fetch fresh data in the background
55
  try {
56
  const response = await getAnalysisResults(1000, 0);
57
  setUserAnalysisData(response.results);
58
+ // Cache the fresh data
59
+ cacheAnalysisData(response.results);
60
  } catch (err) {
61
+ // Only show error if we don't have cached data
62
+ if (!cachedData || cachedData.length === 0) {
63
+ setStatsError(formatError(err));
64
+ }
65
  } finally {
66
  setIsLoadingStats(false);
67
+ setIsRefreshingStats(false);
68
  }
69
  };
70
 
 
149
  // Refresh user analysis data after successful analysis
150
  const updatedResponse = await getAnalysisResults(1000, 0);
151
  setUserAnalysisData(updatedResponse.results);
152
+ // Cache the updated data
153
+ cacheAnalysisData(updatedResponse.results);
154
  } catch (err) {
155
  setError(formatError(err));
156
  } finally {
 
164
  {/* Statistics Section */}
165
  <div className="rounded-lg border border-slate-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 shadow-sm">
166
  <div className="border-b border-slate-200 dark:border-zinc-700 px-6 py-4">
167
+ <div className="flex items-center justify-between">
168
+ <div>
169
+ <h2 className="text-lg font-semibold text-slate-800 dark:text-white">
170
+ Your Analysis Statistics
171
+ </h2>
172
+ <p className="text-sm text-slate-500 dark:text-zinc-400">
173
+ Overview of all your analyzed arguments
174
+ </p>
175
+ </div>
176
+ {isRefreshingStats && (
177
+ <div className="flex items-center gap-2 text-xs text-slate-500 dark:text-zinc-400">
178
+ <div className="h-3 w-3 animate-spin rounded-full border-2 border-slate-300 dark:border-zinc-600 border-t-blue-600 dark:border-t-blue-500"></div>
179
+ <span>Updating...</span>
180
+ </div>
181
+ )}
182
+ </div>
183
  </div>
184
 
185
  {isLoadingStats ? (
src/app/utils/cache.utils.ts ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Cache utilities for storing and retrieving analysis data
3
+ */
4
+
5
+ import type { AnalysisResult } from '../types/analysis.types.ts';
6
+
7
+ const CACHE_KEY = 'analysis_data_cache';
8
+ const CACHE_TIMESTAMP_KEY = 'analysis_data_cache_timestamp';
9
+
10
+ type CachedAnalysisData = {
11
+ results: AnalysisResult[];
12
+ timestamp: number;
13
+ };
14
+
15
+ /**
16
+ * Cache analysis results to localStorage
17
+ */
18
+ export function cacheAnalysisData(results: AnalysisResult[]): void {
19
+ try {
20
+ const cacheData: CachedAnalysisData = {
21
+ results,
22
+ timestamp: Date.now(),
23
+ };
24
+ localStorage.setItem(CACHE_KEY, JSON.stringify(cacheData));
25
+ localStorage.setItem(CACHE_TIMESTAMP_KEY, String(cacheData.timestamp));
26
+ } catch (error) {
27
+ // Silently fail if localStorage is not available or quota exceeded
28
+ console.warn('Failed to cache analysis data:', error);
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Get cached analysis results from localStorage
34
+ */
35
+ export function getCachedAnalysisData(): AnalysisResult[] | null {
36
+ try {
37
+ const cached = localStorage.getItem(CACHE_KEY);
38
+ if (!cached) return null;
39
+
40
+ const cacheData: CachedAnalysisData = JSON.parse(cached);
41
+ return cacheData.results;
42
+ } catch (error) {
43
+ // Silently fail if localStorage is not available or data is corrupted
44
+ console.warn('Failed to retrieve cached analysis data:', error);
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Get cache timestamp
51
+ */
52
+ export function getCacheTimestamp(): number | null {
53
+ try {
54
+ const timestamp = localStorage.getItem(CACHE_TIMESTAMP_KEY);
55
+ return timestamp ? Number(timestamp) : null;
56
+ } catch (error) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Clear cached analysis data
63
+ */
64
+ export function clearAnalysisCache(): void {
65
+ try {
66
+ localStorage.removeItem(CACHE_KEY);
67
+ localStorage.removeItem(CACHE_TIMESTAMP_KEY);
68
+ } catch (error) {
69
+ console.warn('Failed to clear analysis cache:', error);
70
+ }
71
+ }
72
+
src/app/utils/index.ts CHANGED
@@ -10,6 +10,9 @@ export * from './user.utils.ts';
10
  // Export analysis utilities
11
  export * from './analysis.utils.ts';
12
 
 
 
 
13
  /**
14
  * Debounce function - delays execution until after wait time
15
  */
 
10
  // Export analysis utilities
11
  export * from './analysis.utils.ts';
12
 
13
+ // Export cache utilities
14
+ export * from './cache.utils.ts';
15
+
16
  /**
17
  * Debounce function - delays execution until after wait time
18
  */