mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-23 15:18:16 +02:00
feat: Implement initial Noteflow application UI, foundational notes management, and mobile notes page.
This commit is contained in:
1 parent
ad3f415469
commit
4ba078bf4e
4 files changed
+60
-7
No files matched your search
@@ -38,6 +38,30 @@ const upload = multer({
|
|||||||
// Toutes les routes nécessitent authentification
|
// Toutes les routes nécessitent authentification
|
||||||
router.use(authenticateToken);
|
router.use(authenticateToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/notes/counts
|
||||||
|
* Récupérer le nombre de notes actives et archivées
|
||||||
|
*/
|
||||||
|
router.get('/counts', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const activeCount = await getAll(`
|
||||||
|
SELECT COUNT(*) as count FROM notes WHERE user_id = $1 AND archived = false
|
||||||
|
`, [req.user.id]);
|
||||||
|
|
||||||
|
const archivedCount = await getAll(`
|
||||||
|
SELECT COUNT(*) as count FROM notes WHERE user_id = $1 AND archived = true
|
||||||
|
`, [req.user.id]);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
active: parseInt(activeCount[0]?.count || 0),
|
||||||
|
archived: parseInt(archivedCount[0]?.count || 0)
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Erreur lors de la récupération des compteurs:', error);
|
||||||
|
res.status(500).json({ error: 'Erreur serveur' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /api/notes?archived=true/false
|
* GET /api/notes?archived=true/false
|
||||||
* Liste toutes les notes de l'utilisateur
|
* Liste toutes les notes de l'utilisateur
|
||||||
|
|||||||
+9
-3
@@ -159,6 +159,7 @@ const Index = () => {
|
|||||||
const [rssFeeds, setRssFeeds] = useState<RssFeed[]>([]);
|
const [rssFeeds, setRssFeeds] = useState<RssFeed[]>([]);
|
||||||
const [rssArticles, setRssArticles] = useState<RssArticle[]>([]);
|
const [rssArticles, setRssArticles] = useState<RssArticle[]>([]);
|
||||||
const [calendarEvents, setCalendarEvents] = useState<CalendarEvent[]>([]);
|
const [calendarEvents, setCalendarEvents] = useState<CalendarEvent[]>([]);
|
||||||
|
const [counts, setCounts] = useState({ active: 0, archived: 0 });
|
||||||
const [settings, setSettings] = useState<AppSettings>({});
|
const [settings, setSettings] = useState<AppSettings>({});
|
||||||
const [adminTab, setAdminTab] = useState("users");
|
const [adminTab, setAdminTab] = useState("users");
|
||||||
const [showArchived, setShowArchived] = useState(false);
|
const [showArchived, setShowArchived] = useState(false);
|
||||||
@@ -303,10 +304,15 @@ const Index = () => {
|
|||||||
|
|
||||||
const loadNotes = async () => {
|
const loadNotes = async () => {
|
||||||
try {
|
try {
|
||||||
const fetchedNotes = await NotesService.getNotes(showArchived);
|
const [fetchedNotes, fetchedCounts] = await Promise.all([
|
||||||
|
NotesService.getNotes(showArchived),
|
||||||
|
NotesService.getCounts()
|
||||||
|
]);
|
||||||
|
|
||||||
if (Array.isArray(fetchedNotes)) {
|
if (Array.isArray(fetchedNotes)) {
|
||||||
setNotes(fetchedNotes);
|
setNotes(fetchedNotes);
|
||||||
}
|
}
|
||||||
|
setCounts(fetchedCounts);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors du chargement des notes:", error);
|
console.error("Erreur lors du chargement des notes:", error);
|
||||||
}
|
}
|
||||||
@@ -1352,13 +1358,13 @@ const Index = () => {
|
|||||||
variant={!showArchived ? "default" : "outline"}
|
variant={!showArchived ? "default" : "outline"}
|
||||||
onClick={() => setShowArchived(false)}
|
onClick={() => setShowArchived(false)}
|
||||||
>
|
>
|
||||||
Actives ({notes.filter(n => !n.archived).length})
|
Actives ({counts.active})
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={showArchived ? "default" : "outline"}
|
variant={showArchived ? "default" : "outline"}
|
||||||
onClick={() => setShowArchived(true)}
|
onClick={() => setShowArchived(true)}
|
||||||
>
|
>
|
||||||
Archivées ({notes.filter(n => n.archived).length})
|
Archivées ({counts.archived})
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,10 +31,16 @@ export default function NotesPage() {
|
|||||||
const [viewMode, setViewMode] = useState<'list' | 'kanban'>('list');
|
const [viewMode, setViewMode] = useState<'list' | 'kanban'>('list');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const [counts, setCounts] = useState({ active: 0, archived: 0 });
|
||||||
|
|
||||||
const loadNotes = async () => {
|
const loadNotes = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await NotesService.getNotes(showArchived);
|
const [notesData, countsData] = await Promise.all([
|
||||||
setNotes(data);
|
NotesService.getNotes(showArchived),
|
||||||
|
NotesService.getCounts()
|
||||||
|
]);
|
||||||
|
setNotes(notesData);
|
||||||
|
setCounts(countsData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError("Erreur lors du chargement des notes");
|
showError("Erreur lors du chargement des notes");
|
||||||
}
|
}
|
||||||
@@ -184,7 +190,7 @@ export default function NotesPage() {
|
|||||||
}}
|
}}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
>
|
>
|
||||||
Actives ({notes.filter(n => !n.archived).length})
|
Actives ({counts.active})
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={showArchived ? "default" : "outline"}
|
variant={showArchived ? "default" : "outline"}
|
||||||
@@ -195,7 +201,7 @@ export default function NotesPage() {
|
|||||||
}}
|
}}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
>
|
>
|
||||||
Archivées ({notes.filter(n => n.archived).length})
|
Archivées ({counts.archived})
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,23 @@ class NotesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCounts(): Promise<{ active: number; archived: number }> {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/notes/counts", {
|
||||||
|
headers: AuthService.getHeaders()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Erreur lors de la récupération des compteurs");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur compteur:", error);
|
||||||
|
return { active: 0, archived: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async createNote(title: string, content: string = ""): Promise<Note | null> {
|
async createNote(title: string, content: string = ""): Promise<Note | null> {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/notes", {
|
const response = await fetch("/api/notes", {
|
||||||
|
|||||||
Reference in new issue
Block a user