summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b469435)
raw | patch | inline | side by side (parent: b469435)
author | Eric Wertz <ericwertz@Erics-MacBook-Pro.local> | |
Thu, 19 Jun 2025 16:20:34 +0000 (12:20 -0400) | ||
committer | Eric Wertz <ericwertz@Erics-MacBook-Pro.local> | |
Thu, 19 Jun 2025 16:20:34 +0000 (12:20 -0400) |
frontend/app/AppContext.tsx | patch | blob | history | |
frontend/components/ListContext.tsx | patch | blob | history | |
frontend/views/Login.tsx | patch | blob | history |
index 5acbb61a645f981249e9216aa6afada72dfef431..80e984af0bca4b14f5bc5124fd86a196cdebfc0e 100644 (file)
user: User | null;
setUser: (user: User) => void;
checkAuth: () => void;
user: User | null;
setUser: (user: User) => void;
checkAuth: () => void;
- fetchData: (url: string) => Promise<any>;
+ fetchData: (url: string, body?: any) => Promise<any>;
logout: () => void;
}
logout: () => void;
}
checkAuth: async () => {
// Ensure isLoading is true at the beginning of the check
if (!this.state.isLoading) {
checkAuth: async () => {
// Ensure isLoading is true at the beginning of the check
if (!this.state.isLoading) {
- this.state.setIsLoading(true);
+ this.setState({ isLoading: true });
}
try {
const response = await fetch('/auth/check', { credentials: 'include' });
const data = await response.json();
if (data.status !== 'success') {
}
try {
const response = await fetch('/auth/check', { credentials: 'include' });
const data = await response.json();
if (data.status !== 'success') {
- this.state.setLoggedIn(false);
+ this.setState({ loggedIn: false });
// Optionally set user to null if not successful
// Optionally set user to null if not successful
- // this.state.setUser(null);
+ // this.setState({ user: null });
return; // Early return if auth check fails
}
return; // Early return if auth check fails
}
- this.state.setLoggedIn(true);
- this.state.setUser({
- username: data.data.username,
- uuid: data.data.uuid,
+ this.setState({
+ loggedIn: true,
+ user: {
+ username: data.data.username,
+ uuid: data.data.uuid,
+ }
});
} catch (error) {
console.error('Error during auth check:', error);
});
} catch (error) {
console.error('Error during auth check:', error);
- this.state.setLoggedIn(false);
- // Optionally set user to null on error
- // this.state.setUser(null);
- this.state.setNotification({
- visible: true,
- message: 'Error checking authentication status',
- showSpinner: false,
- type: 'error',
+ this.setState({
+ loggedIn: false,
+ notification: {
+ visible: true,
+ message: 'Error checking authentication status',
+ showSpinner: false,
+ type: 'error',
+ }
});
});
+ // Optionally set user to null on error
+ // this.setState({ user: null });
} finally {
// This will always run, ensuring isLoading is set to false
} finally {
// This will always run, ensuring isLoading is set to false
- this.state.setIsLoading(false);
+ this.setState({ isLoading: false });
}
},
}
},
- fetchData: async (url: string) => {
- return fetch(url, { credentials: 'include' })
+ fetchData: async (url: string, body?: any) => {
+ return fetch(url, {
+ credentials: 'include',
+ method: body ? 'POST' : 'GET',
+ headers: body ? { 'Content-Type': 'application/json' } : undefined,
+ body: body ? JSON.stringify(body) : undefined
+ })
.then(response => {
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
.then(response => {
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
return response.json();
})
.catch(error => {
return response.json();
})
.catch(error => {
+ console.log('error', error);
console.error('[LoadError]', error);
console.error('[LoadError]', error);
- this.state.setNotification({
- visible: true,
- message: error.message || 'Failed to load list. Please check connection.',
- showSpinner: false,
- type: 'error',
+ this.setState({
+ notification: {
+ visible: true,
+ message: error.message || 'Failed to load data. Please check connection.',
+ showSpinner: false,
+ type: 'error',
+ }
});
return null;
})
.finally(() => {
});
return null;
})
.finally(() => {
- this.state.setIsLoading(false);
+ this.setState({ isLoading: false });
});
},
logout: () => {
});
},
logout: () => {
index c26a02e27fb61b98d00e75b3e1a357b8e44d62de..92da97ca1abbd6e5ad35bc5a72b7bbdb47b8f502 100644 (file)
}));
};
}));
};
+ // Recursively set level values based on position in the tree (depth)
+ const applyItemLevels = (items: ItemProps[], level: number = 0): ItemProps[] => {
+ return items.map(item => ({
+ ...item,
+ level,
+ _children: applyItemLevels(item._children, level + 1)
+ }));
+ };
+
+ // Adjust an item's level (and its descendants) by a delta value
+ const adjustLevels = (item: ItemProps, delta: number): ItemProps => {
+ const newLevel = Math.max(0, item.level + delta);
+ return {
+ ...item,
+ level: newLevel,
+ __is_dirty: true,
+ _children: item._children.map(child => adjustLevels(child, delta))
+ };
+ };
+
const fetchItems = async () => {
try {
const response = await fetchData('/list/fetch') as { data: ItemProps[] };
if (response?.data?.length > 0) {
const itemsWithOrders = ensureItemOrders(response.data);
const fetchItems = async () => {
try {
const response = await fetchData('/list/fetch') as { data: ItemProps[] };
if (response?.data?.length > 0) {
const itemsWithOrders = ensureItemOrders(response.data);
- setItems(itemsWithOrders);
- //setFocusedItemUuid(itemsWithOrders[0]._uuid);
+ const itemsWithLevels = applyItemLevels(itemsWithOrders);
+ setItems(itemsWithLevels);
+ //setFocusedItemUuid(itemsWithLevels[0]._uuid);
} else {
// Create default empty item
const defaultItem: ItemProps = {
} else {
// Create default empty item
const defaultItem: ItemProps = {
if (flatItems.length === 0) return;
setSaveStatus('saving');
if (flatItems.length === 0) return;
setSaveStatus('saving');
- const response = await fetch('/list/save', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- credentials: 'include',
- body: JSON.stringify(flatItems)
- });
+ const response = await fetchData('/list/save', flatItems);
if (!response.ok) throw new Error(`Save failed: ${response.status}`);
if (!response.ok) throw new Error(`Save failed: ${response.status}`);
_type: 'item',
_created_at: new Date().toISOString(),
_updated_at: new Date().toISOString(),
_type: 'item',
_created_at: new Date().toISOString(),
_updated_at: new Date().toISOString(),
- _children: [],
+ _children: currentItem._children, // Inherit children from current item
__is_new: true,
__is_dirty: true,
content: afterContent,
__is_new: true,
__is_dirty: true,
content: afterContent,
};
setItems(prevItems => {
};
setItems(prevItems => {
- // Update current item
+ // Update current item - remove children and update content
const updatedItems = updateItemInTree(prevItems, currentItem._uuid, item => ({
...item,
content: beforeContent,
const updatedItems = updateItemInTree(prevItems, currentItem._uuid, item => ({
...item,
content: beforeContent,
+ _children: [], // Remove children from current item
__is_dirty: true
}));
__is_dirty: true
}));
__is_dirty: true
}));
__is_dirty: true
}));
- // Insert after parent with updated level
- const promotedItem = { ...currentItem, level: Math.max(0, currentItem.level - 1), __is_dirty: true };
+ // Insert after parent with updated level (also adjust descendants)
+ const promotedItem = adjustLevels(currentItem, -1);
const insertAfterParent = (items: ItemProps[], parentUuid: string): ItemProps[] => {
for (let i = 0; i < items.length; i++) {
if (items[i]._uuid === parentUuid) {
const insertAfterParent = (items: ItemProps[], parentUuid: string): ItemProps[] => {
for (let i = 0; i < items.length; i++) {
if (items[i]._uuid === parentUuid) {
: reorderItems(prevItems.filter(item => item._uuid !== currentItem._uuid));
// Add as child of previous sibling
: reorderItems(prevItems.filter(item => item._uuid !== currentItem._uuid));
// Add as child of previous sibling
- const demotedItem = {
- ...currentItem,
- level: currentItem.level + 1,
- __is_dirty: true
- };
+ const demotedItem = adjustLevels(currentItem, 1);
result = updateItemInTree(result, previousSibling._uuid, sibling => ({
...sibling,
result = updateItemInTree(result, previousSibling._uuid, sibling => ({
...sibling,
index ef34034ef18e433c92d89ef8df1b1e28459fb171..1b08b95e0fc8f688a2faab4cc2eea29ab50e09c9 100644 (file)
--- a/frontend/views/Login.tsx
+++ b/frontend/views/Login.tsx
import { h } from "preact";
import { h } from "preact";
+import { useContext } from "preact/hooks";
+import { AppContext } from "../app/AppContext";
const Login = () => {
const Login = () => {
+ const { fetchData } = useContext(AppContext);
+
const handleSubmit = async (e: Event) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const handleSubmit = async (e: Event) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
};
try {
};
try {
- const response = await fetch('/auth/login', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- credentials: 'include',
- body: JSON.stringify(data)
- });
+ const response = await fetchData('/auth/login', data);
- if (!response.ok) {
- throw new Error('Login failed');
+ if (!response) {
+ console.error('Login failed');
+ return;
}
// Handle successful login here
}
// Handle successful login here