fix: explicit double click handler on cards, explicit create button on related fields, and correct RBAC labels parsing
This commit is contained in:
parent
682d6620b9
commit
6d83697def
@ -10,7 +10,7 @@
|
|||||||
* - The `onEdit` callback is injected by the parent — this component stays pure.
|
* - The `onEdit` callback is injected by the parent — this component stays pure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useRef } from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Edit2, Trash2, Eye, Calendar, Tag } from 'lucide-react';
|
import { Edit2, Trash2, Eye, Calendar, Tag } from 'lucide-react';
|
||||||
import { Post, PostCardProps, UserRole } from '@/types/publications';
|
import { Post, PostCardProps, UserRole } from '@/types/publications';
|
||||||
@ -81,16 +81,36 @@ export const PostCard: React.FC<PostCardProps> = ({
|
|||||||
? post.tipo_publicacion_id.descripcion
|
? post.tipo_publicacion_id.descripcion
|
||||||
: post.tipo_publicacion_id;
|
: post.tipo_publicacion_id;
|
||||||
|
|
||||||
|
const clickTimer = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
const handleCardClick = (e: React.MouseEvent) => {
|
const handleCardClick = (e: React.MouseEvent) => {
|
||||||
if ((e.target as HTMLElement).closest('button, a, [role="button"]')) return;
|
if ((e.target as HTMLElement).closest('button, a, [role="button"]')) return;
|
||||||
// Single click: abre vista de detalle
|
|
||||||
|
// Clear previous timer if any
|
||||||
|
if (clickTimer.current) {
|
||||||
|
clearTimeout(clickTimer.current);
|
||||||
|
clickTimer.current = null;
|
||||||
|
return; // It's a double click, let onDoubleClick handle it
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a timer to wait and see if it's a single or double click
|
||||||
|
clickTimer.current = setTimeout(() => {
|
||||||
window.open(`/${post.slug || post.$id}`, '_blank');
|
window.open(`/${post.slug || post.$id}`, '_blank');
|
||||||
|
clickTimer.current = null;
|
||||||
|
}, 250);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCardDoubleClick = (e: React.MouseEvent) => {
|
const handleCardDoubleClick = (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (clickTimer.current) {
|
||||||
|
clearTimeout(clickTimer.current);
|
||||||
|
clickTimer.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
if ((e.target as HTMLElement).closest('button, a, [role="button"]')) return;
|
if ((e.target as HTMLElement).closest('button, a, [role="button"]')) return;
|
||||||
|
|
||||||
// Double click: abre edición si es admin/editor
|
// Double click: abre edición si es admin/editor
|
||||||
if (userRole === 'admin' || userRole === 'editor') {
|
if (userRole === 'admin' || userRole === 'editor') {
|
||||||
onEdit?.(post);
|
onEdit?.(post);
|
||||||
|
|||||||
@ -74,7 +74,8 @@ export const PublicationsList: React.FC<PublicationsListProps> = ({
|
|||||||
// Lazy-load Drawer to avoid shipping it unless needed
|
// Lazy-load Drawer to avoid shipping it unless needed
|
||||||
const [DrawerComponent, setDrawerComponent] = useState<React.ComponentType<import('./PublicationDrawer').PublicationDrawerProps> | null>(null);
|
const [DrawerComponent, setDrawerComponent] = useState<React.ComponentType<import('./PublicationDrawer').PublicationDrawerProps> | null>(null);
|
||||||
|
|
||||||
const userRole = (user?.prefs?.role as UserRole) ?? 'viewer';
|
const canEdit = user?.$id === 'admin-emergency' || user?.labels?.includes('admin') || user?.labels?.includes('editor');
|
||||||
|
const userRole = canEdit ? 'admin' : 'viewer';
|
||||||
|
|
||||||
// ── DERIVED STATE ────────────────────────────
|
// ── DERIVED STATE ────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@ -261,7 +261,7 @@ export const RelationSelectField: React.FC<RelationSelectFieldProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-1.5 w-full">
|
<div className="flex flex-col gap-1.5 w-full">
|
||||||
{/* Label with hint */}
|
{/* Label with Explicit Quick Create Action */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label
|
<label
|
||||||
htmlFor={`field-${name}`}
|
htmlFor={`field-${name}`}
|
||||||
@ -270,10 +270,15 @@ export const RelationSelectField: React.FC<RelationSelectFieldProps> = ({
|
|||||||
{label}
|
{label}
|
||||||
{required && <span className="text-cyan-400 ml-1">*</span>}
|
{required && <span className="text-cyan-400 ml-1">*</span>}
|
||||||
</label>
|
</label>
|
||||||
<span className="flex items-center gap-1 text-[9px] text-slate-600 font-bold uppercase tracking-wider">
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={(e) => { e.preventDefault(); handleDoubleClick(); }}
|
||||||
|
className="flex items-center gap-1.5 text-[10px] bg-cyan-500/10 text-cyan-400 hover:bg-cyan-500/20 px-2 py-1 rounded-md font-bold uppercase tracking-wider transition-colors border border-cyan-500/20"
|
||||||
|
title="Añadir una nueva opción a la base de datos"
|
||||||
|
>
|
||||||
<MousePointerClick size={10} />
|
<MousePointerClick size={10} />
|
||||||
Doble-click para crear nuevo
|
Crear Nuevo
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Select Wrapper */}
|
{/* Select Wrapper */}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export interface AuthUser {
|
|||||||
$id: string;
|
$id: string;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
labels?: string[];
|
||||||
prefs: {
|
prefs: {
|
||||||
role?: UserRole;
|
role?: UserRole;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user