* Replace quick capture * Transfer to inbox * Fix inbox edit * fixup! Fix inbox edit * fixup! fixup! Fix inbox edit * fixup! fixup! fixup! Fix inbox edit * fixup! fixup! fixup! fixup! Fix inbox edit * fixup! fixup! fixup! fixup! fixup! Fix inbox edit * Add long text * fixup! Add long text * fixup! fixup! Add long text * fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text * fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! Add long text
276 lines
8.1 KiB
TypeScript
276 lines
8.1 KiB
TypeScript
import { InboxItem } from '../entities/InboxItem';
|
|
import { useStore } from '../store/useStore';
|
|
import { handleAuthResponse } from './authUtils';
|
|
import { getApiPath } from '../config/paths';
|
|
|
|
// API functions
|
|
export const fetchInboxItems = async (
|
|
limit: number = 20,
|
|
offset: number = 0
|
|
): Promise<{
|
|
items: InboxItem[];
|
|
pagination: {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
hasMore: boolean;
|
|
};
|
|
}> => {
|
|
const params = new URLSearchParams({
|
|
limit: limit.toString(),
|
|
offset: offset.toString(),
|
|
});
|
|
|
|
const response = await fetch(getApiPath(`inbox?${params}`), {
|
|
credentials: 'include',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
},
|
|
});
|
|
|
|
await handleAuthResponse(response, 'Failed to fetch inbox items.');
|
|
|
|
const result = await response.json();
|
|
|
|
// Handle backward compatibility - if it's an array, convert to new format
|
|
if (Array.isArray(result)) {
|
|
return {
|
|
items: result,
|
|
pagination: {
|
|
total: result.length,
|
|
limit: result.length,
|
|
offset: 0,
|
|
hasMore: false,
|
|
},
|
|
};
|
|
}
|
|
|
|
if (!result.items || !Array.isArray(result.items)) {
|
|
throw new Error('Resulting inbox items are not in expected format.');
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
export const createInboxItem = async (
|
|
content: string,
|
|
source?: string
|
|
): Promise<InboxItem> => {
|
|
const response = await fetch(getApiPath('inbox'), {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
},
|
|
body: JSON.stringify(source ? { content, source } : { content }),
|
|
});
|
|
|
|
await handleAuthResponse(response, 'Failed to create inbox item.');
|
|
return await response.json();
|
|
};
|
|
|
|
export const updateInboxItem = async (
|
|
itemUid: string,
|
|
content: string
|
|
): Promise<InboxItem> => {
|
|
const response = await fetch(getApiPath(`inbox/${itemUid}`), {
|
|
method: 'PATCH',
|
|
credentials: 'include',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
},
|
|
body: JSON.stringify({ content }),
|
|
});
|
|
|
|
await handleAuthResponse(response, 'Failed to update inbox item.');
|
|
return await response.json();
|
|
};
|
|
|
|
export const processInboxItem = async (itemUid: string): Promise<InboxItem> => {
|
|
const response = await fetch(getApiPath(`inbox/${itemUid}/process`), {
|
|
method: 'PATCH',
|
|
credentials: 'include',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
},
|
|
});
|
|
|
|
await handleAuthResponse(response, 'Failed to process inbox item.');
|
|
return await response.json();
|
|
};
|
|
|
|
export const deleteInboxItem = async (itemUid: string): Promise<void> => {
|
|
const response = await fetch(getApiPath(`inbox/${itemUid}`), {
|
|
method: 'DELETE',
|
|
credentials: 'include',
|
|
headers: {
|
|
Accept: 'application/json',
|
|
},
|
|
});
|
|
|
|
await handleAuthResponse(response, 'Failed to delete inbox item.');
|
|
};
|
|
|
|
// Track last check time to detect new items
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const lastCheckTimestamp = Date.now();
|
|
|
|
// Store-aware functions
|
|
export const loadInboxItemsToStore = async (
|
|
isInitialLoad: boolean = false,
|
|
requestedCount: number = 20
|
|
): Promise<void> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
// Only show loading for initial load, not for polling
|
|
if (isInitialLoad && inboxStore.inboxItems.length === 0) {
|
|
inboxStore.setLoading(true);
|
|
inboxStore.resetPagination();
|
|
}
|
|
|
|
try {
|
|
// Load the requested number of items (for pagination preservation)
|
|
const { items, pagination } = await fetchInboxItems(requestedCount, 0);
|
|
|
|
// Check for new items since last check (only for non-initial loads)
|
|
if (!isInitialLoad) {
|
|
const currentItemUids = new Set(
|
|
inboxStore.inboxItems.map((item) => item.uid).filter(Boolean)
|
|
);
|
|
|
|
// New telegram items
|
|
const newTelegramItems = items.filter(
|
|
(item) =>
|
|
item.uid &&
|
|
!currentItemUids.has(item.uid) &&
|
|
item.source === 'telegram'
|
|
);
|
|
|
|
// Only show notifications if we have detected changes
|
|
if (
|
|
inboxStore.inboxItems.length > 0 &&
|
|
newTelegramItems.length > 0
|
|
) {
|
|
// Get some minimal info about the items for the notification
|
|
const previewSource =
|
|
newTelegramItems[0].title ||
|
|
newTelegramItems[0].content ||
|
|
'';
|
|
const notificationData = {
|
|
count: newTelegramItems.length,
|
|
firstItemContent:
|
|
previewSource.substring(0, 30) +
|
|
(previewSource.length > 30 ? '...' : ''),
|
|
};
|
|
|
|
// Dispatch a custom event with the notification data
|
|
window.dispatchEvent(
|
|
new CustomEvent('inboxItemsUpdated', {
|
|
detail: notificationData,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
// Update state
|
|
inboxStore.setInboxItems(items);
|
|
inboxStore.setPagination(pagination);
|
|
inboxStore.setError(false);
|
|
} catch (error) {
|
|
console.error('Failed to load inbox items:', error);
|
|
inboxStore.setError(true);
|
|
} finally {
|
|
// Only set loading to false if we were actually loading
|
|
if (isInitialLoad) {
|
|
inboxStore.setLoading(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
export const loadMoreInboxItemsToStore = async (): Promise<void> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
|
|
if (!inboxStore.pagination.hasMore || inboxStore.isLoading) {
|
|
return;
|
|
}
|
|
|
|
inboxStore.setLoading(true);
|
|
|
|
try {
|
|
const nextOffset =
|
|
inboxStore.pagination.offset + inboxStore.pagination.limit;
|
|
const { items, pagination } = await fetchInboxItems(20, nextOffset);
|
|
|
|
// Append new items to existing ones
|
|
inboxStore.appendInboxItems(items);
|
|
inboxStore.setPagination(pagination);
|
|
inboxStore.setError(false);
|
|
} catch (error) {
|
|
console.error('Failed to load more inbox items:', error);
|
|
inboxStore.setError(true);
|
|
} finally {
|
|
inboxStore.setLoading(false);
|
|
}
|
|
};
|
|
|
|
export const createInboxItemWithStore = async (
|
|
content: string,
|
|
source?: string
|
|
): Promise<InboxItem> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
|
|
try {
|
|
const newItem = await createInboxItem(content, source);
|
|
inboxStore.addInboxItem(newItem);
|
|
return newItem;
|
|
} catch (error) {
|
|
console.error('Failed to create inbox item:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
export const updateInboxItemWithStore = async (
|
|
itemUid: string,
|
|
content: string
|
|
): Promise<InboxItem> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
|
|
try {
|
|
const updatedItem = await updateInboxItem(itemUid, content);
|
|
inboxStore.updateInboxItem(updatedItem);
|
|
return updatedItem;
|
|
} catch (error) {
|
|
console.error('Failed to update inbox item:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
export const processInboxItemWithStore = async (
|
|
itemUid: string
|
|
): Promise<InboxItem> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
|
|
try {
|
|
const processedItem = await processInboxItem(itemUid);
|
|
inboxStore.removeInboxItemByUid(itemUid);
|
|
return processedItem;
|
|
} catch (error) {
|
|
console.error('Failed to process inbox item:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
export const deleteInboxItemWithStore = async (
|
|
itemUid: string
|
|
): Promise<void> => {
|
|
const inboxStore = useStore.getState().inboxStore;
|
|
|
|
try {
|
|
await deleteInboxItem(itemUid);
|
|
inboxStore.removeInboxItemByUid(itemUid);
|
|
} catch (error) {
|
|
console.error('Failed to delete inbox item:', error);
|
|
throw error;
|
|
}
|
|
};
|