0964ffb8a8
Nueva columna sort_order en notes (migracion 020, mismo patron que 012_sort_order.sql de activities/tasks). Se reusa el hook useDragReorder ya existente (drag & drop nativo, sin libreria nueva) -- el icono de agarre va solo en una esquina de la tarjeta, nunca en la tarjeta completa, para no pisar el click que abre la edicion (mismo truco que ya usa ListView.jsx: stopPropagation en el handle). Solo las notas propias son arrastrables/reordenables; las compartidas conmigo quedan siempre despues, ordenadas por fecha (el orden manual de otro usuario no tiene sentido para mi vista). Se desactiva mientras hay un filtro de busqueda activo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
74 lines
3.0 KiB
JavaScript
74 lines
3.0 KiB
JavaScript
import { pool } from '../../config/db.js';
|
|
|
|
// Notas propias MAS las compartidas conmigo. is_owner permite al frontend decidir si se puede
|
|
// editar/borrar/compartir/arrastrar (siempre false para una nota compartida: el dueno nunca
|
|
// cambia, y el orden manual de otro usuario no tiene sentido para mi vista). Propias primero (en
|
|
// su orden manual), compartidas despues (por fecha -- nunca arrastrables).
|
|
export async function findVisibleToUser(userId) {
|
|
const [rows] = await pool.query(
|
|
`SELECT n.id, n.user_id, n.content, n.created_at, n.updated_at,
|
|
(n.user_id = ?) AS is_owner, u.name AS owner_name,
|
|
(SELECT COUNT(*) FROM note_shares ns WHERE ns.note_id = n.id) AS share_count
|
|
FROM notes n
|
|
JOIN users u ON u.id = n.user_id
|
|
WHERE n.user_id = ? OR n.id IN (SELECT note_id FROM note_shares WHERE user_id = ?)
|
|
ORDER BY is_owner DESC, CASE WHEN is_owner THEN n.sort_order ELSE 0 END DESC, n.updated_at DESC`,
|
|
[userId, userId, userId]
|
|
);
|
|
return rows.map((r) => ({ ...r, is_owner: !!r.is_owner, share_count: Number(r.share_count) }));
|
|
}
|
|
|
|
// Posiciones SIEMPRE N..1 (nunca 0 -- ver migracion 020). El primer id del arreglo (arriba del
|
|
// todo visualmente) recibe el numero MAS ALTO porque el ORDER BY de arriba es DESC. Solo toca
|
|
// notas propias de userId, ignora cualquier id ajeno que venga en la lista.
|
|
export async function reorder(userId, ids) {
|
|
const total = ids.length;
|
|
for (let i = 0; i < total; i++) {
|
|
await pool.query('UPDATE notes SET sort_order = ? WHERE id = ? AND user_id = ?', [total - i, ids[i], userId]);
|
|
}
|
|
}
|
|
|
|
export async function findById(id) {
|
|
const [rows] = await pool.query('SELECT id, user_id, content, created_at, updated_at FROM notes WHERE id = ?', [id]);
|
|
return rows[0] || null;
|
|
}
|
|
|
|
export async function create(userId, content) {
|
|
const [result] = await pool.query('INSERT INTO notes (user_id, content) VALUES (?, ?)', [userId, content]);
|
|
return findById(result.insertId);
|
|
}
|
|
|
|
export async function update(id, content) {
|
|
await pool.query('UPDATE notes SET content = ? WHERE id = ?', [content, id]);
|
|
return findById(id);
|
|
}
|
|
|
|
export async function remove(id) {
|
|
await pool.query('DELETE FROM notes WHERE id = ?', [id]);
|
|
}
|
|
|
|
export async function listShares(noteId) {
|
|
const [rows] = await pool.query(
|
|
`SELECT ns.user_id, u.name, u.email, ns.shared_at
|
|
FROM note_shares ns JOIN users u ON u.id = ns.user_id
|
|
WHERE ns.note_id = ? ORDER BY u.name`,
|
|
[noteId]
|
|
);
|
|
return rows;
|
|
}
|
|
|
|
export async function isSharedWith(noteId, userId) {
|
|
const [rows] = await pool.query('SELECT 1 FROM note_shares WHERE note_id = ? AND user_id = ?', [noteId, userId]);
|
|
return rows.length > 0;
|
|
}
|
|
|
|
export async function addShare(noteId, userId) {
|
|
await pool.query('INSERT IGNORE INTO note_shares (note_id, user_id) VALUES (?, ?)', [noteId, userId]);
|
|
return listShares(noteId);
|
|
}
|
|
|
|
export async function removeShare(noteId, userId) {
|
|
await pool.query('DELETE FROM note_shares WHERE note_id = ? AND user_id = ?', [noteId, userId]);
|
|
return listShares(noteId);
|
|
}
|