Refactor data types in ConflictResolutionDialog and OfflineIndicator components for improved type safety; update OfflineAction interface to use 'unknown' instead of 'any' for data property, and enhance action label handling in OfflineIndicator for better clarity.
This commit is contained in:
parent
db5f2d089e
commit
5a910a29e2
@ -172,11 +172,11 @@ import type { OfflineAction } from 'src/stores/offline';
|
||||
|
||||
interface ConflictData {
|
||||
localVersion: {
|
||||
data: Record<string, any>;
|
||||
data: Record<string, unknown>;
|
||||
timestamp: number;
|
||||
};
|
||||
serverVersion: {
|
||||
data: Record<string, any>;
|
||||
data: Record<string, unknown>;
|
||||
timestamp: number;
|
||||
};
|
||||
action: OfflineAction;
|
||||
@ -189,7 +189,7 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
(e: 'resolve', resolution: { version: 'local' | 'server' | 'merge'; action: OfflineAction; mergedData?: Record<string, any> }): void;
|
||||
(e: 'resolve', resolution: { version: 'local' | 'server' | 'merge'; action: OfflineAction; mergedData?: Record<string, unknown> }): void;
|
||||
}>();
|
||||
|
||||
const show = ref(props.modelValue);
|
||||
@ -229,11 +229,12 @@ const formatKey = (key: string): string => {
|
||||
.replace(/^\w/, (c) => c.toUpperCase());
|
||||
};
|
||||
|
||||
const formatValue = (value: any): string => {
|
||||
const formatValue = (value: unknown): string => {
|
||||
if (value === null || value === undefined) return '-';
|
||||
if (typeof value === 'boolean') return value ? 'Yes' : 'No';
|
||||
if (typeof value === 'object') return JSON.stringify(value);
|
||||
return String(value);
|
||||
if (typeof value === 'number' || typeof value === 'string') return String(value);
|
||||
return '[Unsupported Type]';
|
||||
};
|
||||
|
||||
const isDifferent = (key: string): boolean => {
|
||||
@ -257,7 +258,7 @@ const resolveConflict = (version: 'local' | 'server' | 'merge'): void => {
|
||||
const applyMergedChanges = (): void => {
|
||||
if (!props.conflictData) return;
|
||||
|
||||
const mergedData: Record<string, any> = {};
|
||||
const mergedData: Record<string, unknown> = {};
|
||||
Object.entries(mergeChoices.value).forEach(([key, choice]) => {
|
||||
const localValue = props.conflictData?.localVersion.data[key];
|
||||
const serverValue = props.conflictData?.serverVersion.data[key];
|
||||
@ -285,4 +286,4 @@ const applyMergedChanges = (): void => {
|
||||
color: $positive;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
</style>
|
@ -89,14 +89,22 @@ const {
|
||||
|
||||
const getActionLabel = (action: OfflineAction) => {
|
||||
switch (action.type) {
|
||||
case 'add':
|
||||
return `Add new item: ${action.data.title || 'Untitled'}`;
|
||||
case 'complete':
|
||||
return `Complete item: ${action.data.title || 'Untitled'}`;
|
||||
case 'update':
|
||||
return `Update item: ${action.data.title || 'Untitled'}`;
|
||||
case 'delete':
|
||||
return `Delete item: ${action.data.title || 'Untitled'}`;
|
||||
case 'add': {
|
||||
const data = action.data as { title?: string };
|
||||
return `Add new item: ${data.title || 'Untitled'}`;
|
||||
}
|
||||
case 'complete': {
|
||||
const data = action.data as { title?: string };
|
||||
return `Complete item: ${data.title || 'Untitled'}`;
|
||||
}
|
||||
case 'update': {
|
||||
const data = action.data as { title?: string };
|
||||
return `Update item: ${data.title || 'Untitled'}`;
|
||||
}
|
||||
case 'delete': {
|
||||
const data = action.data as { title?: string };
|
||||
return `Delete item: ${data.title || 'Untitled'}`;
|
||||
}
|
||||
default:
|
||||
return 'Unknown action';
|
||||
}
|
||||
@ -120,4 +128,4 @@ const getActionLabel = (action: OfflineAction) => {
|
||||
background-color: #fff3e0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
@ -7,7 +7,7 @@ export interface OfflineAction {
|
||||
id: string;
|
||||
type: 'add' | 'complete' | 'update' | 'delete';
|
||||
itemId?: string;
|
||||
data: any;
|
||||
data: unknown;
|
||||
timestamp: number;
|
||||
version?: number;
|
||||
}
|
||||
@ -17,16 +17,28 @@ export interface ConflictResolution {
|
||||
action: OfflineAction;
|
||||
}
|
||||
|
||||
export interface ConflictData {
|
||||
localVersion: {
|
||||
data: Record<string, unknown>;
|
||||
timestamp: number;
|
||||
};
|
||||
serverVersion: {
|
||||
data: Record<string, unknown>;
|
||||
timestamp: number;
|
||||
};
|
||||
action: OfflineAction;
|
||||
}
|
||||
|
||||
export const useOfflineStore = defineStore('offline', () => {
|
||||
const $q = useQuasar();
|
||||
const isOnline = ref(navigator.onLine);
|
||||
const pendingActions = ref<OfflineAction[]>([]);
|
||||
const isProcessingQueue = ref(false);
|
||||
const showConflictDialog = ref(false);
|
||||
const currentConflict = ref<ConflictResolution | null>(null);
|
||||
const currentConflict = ref<ConflictData | null>(null);
|
||||
|
||||
// Initialize from IndexedDB
|
||||
const init = async () => {
|
||||
const init = () => {
|
||||
try {
|
||||
const stored = LocalStorage.getItem('offline-actions');
|
||||
if (stored) {
|
||||
@ -66,16 +78,11 @@ export const useOfflineStore = defineStore('offline', () => {
|
||||
|
||||
for (const action of actions) {
|
||||
try {
|
||||
// TODO: Implement actual API calls based on action type
|
||||
// This will be implemented when we have the API endpoints
|
||||
await processAction(action);
|
||||
|
||||
// Remove successful action
|
||||
pendingActions.value = pendingActions.value.filter(a => a.id !== action.id);
|
||||
saveToStorage();
|
||||
} catch (error: any) {
|
||||
if (error.status === 409) {
|
||||
// Handle version conflict
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message.includes('409')) {
|
||||
$q.notify({
|
||||
type: 'warning',
|
||||
message: 'Item was modified by someone else while you were offline. Please review.',
|
||||
@ -101,7 +108,6 @@ export const useOfflineStore = defineStore('offline', () => {
|
||||
// Process a single action
|
||||
const processAction = async (action: OfflineAction) => {
|
||||
// TODO: Implement actual API calls
|
||||
// This is a placeholder that will be replaced with actual API calls
|
||||
switch (action.type) {
|
||||
case 'add':
|
||||
// await api.addItem(action.data);
|
||||
@ -121,8 +127,12 @@ export const useOfflineStore = defineStore('offline', () => {
|
||||
// Listen for online/offline status changes
|
||||
const setupNetworkListeners = () => {
|
||||
window.addEventListener('online', () => {
|
||||
isOnline.value = true;
|
||||
processQueue();
|
||||
(async () => {
|
||||
isOnline.value = true;
|
||||
await processQueue();
|
||||
})().catch(error => {
|
||||
console.error('Error processing queue:', error);
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
@ -154,4 +164,4 @@ export const useOfflineStore = defineStore('offline', () => {
|
||||
processQueue,
|
||||
handleConflictResolution,
|
||||
};
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user