diff --git a/CHANGELOG.md b/CHANGELOG.md index b985833..5a51010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,14 @@ ## Versión actual -- Versión base: `1.2.12` +- Versión base: `1.2.13` ## Historial +### 1.2.13 - 2026-04-27 + +- Web y Android ocultan por defecto los detalles avanzados de `Firmar ahora` y los muestran solo bajo demanda con botón de ojo. + ### 1.2.12 - 2026-04-23 - Web reordena el menú principal para mostrar `Firmar ahora` en segunda posición y `Mis documentos` justo debajo. diff --git a/VERSION b/VERSION index f2ae0b4..0b1f1ed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.12 +1.2.13 diff --git a/android/app/build.gradle b/android/app/build.gradle index 817682f..038ddf8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -18,8 +18,8 @@ android { applicationId "net.linkedcorp.linkedsign" minSdk 26 targetSdk 35 - versionCode 10212 - versionName "1.2.12" + versionCode 10213 + versionName "1.2.13" buildConfigField "String", "API_BASE_URL", "\"${apiBaseUrl}\"" } diff --git a/android/app/src/main/java/net/linkedcorp/linkedsign/ui/LinkedSignApp.kt b/android/app/src/main/java/net/linkedcorp/linkedsign/ui/LinkedSignApp.kt index 71add51..16734b4 100644 --- a/android/app/src/main/java/net/linkedcorp/linkedsign/ui/LinkedSignApp.kt +++ b/android/app/src/main/java/net/linkedcorp/linkedsign/ui/LinkedSignApp.kt @@ -1330,6 +1330,7 @@ private fun SignScreen( var certPassword by rememberSaveable { mutableStateOf("") } var reason by rememberSaveable { mutableStateOf("Firmado digitalmente") } var location by rememberSaveable { mutableStateOf("") } + var showAdvancedOptions by remember { mutableStateOf(false) } var currentPageIndex by rememberSaveable(selectedDocumentId) { mutableStateOf(0) } var preview by remember(selectedDocumentId) { mutableStateOf(null) } var placement by remember(selectedDocumentId) { mutableStateOf(null) } @@ -1339,6 +1340,9 @@ private fun SignScreen( val selectedDocument = state.documents.firstOrNull { it.id.toString() == selectedDocumentId } val signerLabel = state.userName ?: state.userEmail ?: "Firmante" val signatureStyle = state.signaturePreferences?.signatureStyle ?: "qr" + val qrPosition = state.signaturePreferences?.qrPosition ?: "left" + val qrBackground = state.signaturePreferences?.qrBackground ?: "transparent" + val qrBorder = state.signaturePreferences?.qrBorder ?: "none" LaunchedEffect(initialDocumentId, state.documents) { val documentId = initialDocumentId ?: return@LaunchedEffect @@ -1360,7 +1364,6 @@ private fun SignScreen( ) { item { SectionCard(title = "Vista previa y firma") { - Text("Esta versión usa la configuración visual de firma ya guardada en tu cuenta.", color = TextMuted, fontSize = AppFontSizes.sm) DropdownSelector( label = "Documento", options = state.documents.associate { it.id.toString() to (it.title ?: it.filename ?: "Documento ${it.id}") }, @@ -1374,8 +1377,37 @@ private fun SignScreen( onSelect = { selectedCertificateId = it } ) AppTextField(value = certPassword, onValueChange = { certPassword = it }, label = "Contraseña del certificado", isPassword = true) - AppTextField(value = reason, onValueChange = { reason = it }, label = "Razón") - AppTextField(value = location, onValueChange = { location = it }, label = "Ubicación") + OutlinedActionButton( + label = if (showAdvancedOptions) "Ocultar detalles" else "Mostrar detalles", + icon = if (showAdvancedOptions) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility + ) { + showAdvancedOptions = !showAdvancedOptions + } + if (showAdvancedOptions) { + Text("Esta versión usa la configuración visual de firma ya guardada en tu cuenta.", color = TextMuted, fontSize = AppFontSizes.sm) + AppTextField(value = reason, onValueChange = { reason = it }, label = "Razón") + AppTextField(value = location, onValueChange = { location = it }, label = "Ubicación") + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(18.dp), + color = SurfaceSoft, + border = BorderStroke(1.dp, StrokeSoft) + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(6.dp) + ) { + Text("Estilo aplicado", color = BrandDark, fontSize = AppFontSizes.base, fontWeight = FontWeight.SemiBold) + Text("La firma usará tu configuración guardada en el menú Estilo Firma.", color = TextMuted, fontSize = AppFontSizes.sm) + Text("Tipo: $signatureStyle", color = BrandDark, fontSize = AppFontSizes.sm) + if (signatureStyle == "qr") { + Text("Posición QR: ${if (qrPosition == "left") "Izquierda" else "Derecha"}", color = BrandDark, fontSize = AppFontSizes.sm) + Text("Fondo: ${if (qrBackground == "transparent") "Transparente" else "Suave"}", color = BrandDark, fontSize = AppFontSizes.sm) + Text("Borde: ${if (qrBorder == "none") "Sin borde" else "Con borde"}", color = BrandDark, fontSize = AppFontSizes.sm) + } + } + } + } OutlinedActionButton("Cargar PDF para ubicar firma", Icons.Outlined.Description) { val documentId = selectedDocumentId.toIntOrNull() ?: return@OutlinedActionButton scope.launch { diff --git a/backend/package.json b/backend/package.json index bb73407..743660f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "linkedsign-backend", - "version": "1.2.12", + "version": "1.2.13", "private": true, "description": "Initial backend for LinkedSign", "main": "src/server.js", diff --git a/frontend/package.json b/frontend/package.json index a0d7914..7fcbdc6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "1.2.12", + "version": "1.2.13", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/index.css b/frontend/src/index.css index 74905c0..d876b22 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1059,6 +1059,13 @@ select { justify-content: center; } +.btn-inline-toggle { + width: fit-content; + display: inline-flex; + align-items: center; + gap: 8px; +} + .sign-form-card form { display: flex; flex-direction: column; gap: 14px; } .sign-info-panel { display: flex; flex-direction: column; gap: 14px; } @@ -2314,6 +2321,11 @@ select { flex: 1; } + .btn-inline-toggle { + width: 100%; + justify-content: center; + } + .steps-bar { flex-direction: column; align-items: stretch; diff --git a/frontend/src/pages/signatures/SignaturesPage.jsx b/frontend/src/pages/signatures/SignaturesPage.jsx index d7e40a2..0b4a5f2 100644 --- a/frontend/src/pages/signatures/SignaturesPage.jsx +++ b/frontend/src/pages/signatures/SignaturesPage.jsx @@ -3,7 +3,7 @@ import { useSearchParams } from 'react-router-dom'; import { listDocuments, downloadDocument, uploadDocument } from '../../api/documents'; import { listCertificates } from '../../api/certificates'; import { signDocument, getSignatures, downloadSigned } from '../../api/signatures'; -import { PenTool, FileText, Shield, CheckCircle, MapPin, Download, Check, Plus } from 'lucide-react'; +import { PenTool, FileText, Shield, CheckCircle, MapPin, Download, Check, Plus, Eye, EyeOff } from 'lucide-react'; import toast from 'react-hot-toast'; import PasswordModal from '../../components/ui/PasswordModal'; import PdfSignaturePlacer from '../../components/ui/PdfSignaturePlacer'; @@ -40,6 +40,7 @@ export default function SignaturesPage() { const [pendingSign, setPendingSign] = useState(null); const [uploadingDocument, setUploadingDocument] = useState(false); const [pendingLocalDocument, setPendingLocalDocument] = useState(null); + const [showAdvancedOptions, setShowAdvancedOptions] = useState(false); const documentInputRef = useRef(null); useEffect(() => { @@ -293,22 +294,34 @@ export default function SignaturesPage() { {certs.length === 0 && No tienes certificados activos.} -
- - -
-
- - -
-
-

Estilo aplicado

-

La firma usará tu configuración guardada en el menú Estilo Firma.

-

Tipo: {form.signatureStyle}

- {form.signatureStyle === 'qr' &&

Posición QR: {form.qrPosition === 'left' ? 'Izquierda' : 'Derecha'}

} - {form.signatureStyle === 'qr' &&

Fondo: {form.qrBackground === 'transparent' ? 'Transparente' : 'Suave'}

} - {form.signatureStyle === 'qr' &&

Borde: {form.qrBorder === 'none' ? 'Sin borde' : 'Con borde'}

} -
+ + {showAdvancedOptions && ( + <> +
+ + +
+
+ + +
+
+

Estilo aplicado

+

La firma usará tu configuración guardada en el menú Estilo Firma.

+

Tipo: {form.signatureStyle}

+ {form.signatureStyle === 'qr' &&

Posición QR: {form.qrPosition === 'left' ? 'Izquierda' : 'Derecha'}

} + {form.signatureStyle === 'qr' &&

Fondo: {form.qrBackground === 'transparent' ? 'Transparente' : 'Suave'}

} + {form.signatureStyle === 'qr' &&

Borde: {form.qrBorder === 'none' ? 'Sin borde' : 'Con borde'}

} +
+ + )} @@ -372,7 +385,7 @@ export default function SignaturesPage() {

- Haz clic donde quieres que aparezca la firma en {selectedDoc?.title} + Haz clic donde quieres que aparezca la firma en {selectedDocumentTitle}

Posición confirmada — listo para firmar
-

Documento: {selectedDoc?.title}

+

Documento: {selectedDocumentTitle}

Certificado: {selectedCert?.alias}

-

Razón: {form.reason}

- {form.location &&

Ubicación: {form.location}

} -

Estilo visual: {form.signatureStyle}

- {form.signatureStyle === 'qr' &&

Posición QR: {form.qrPosition === 'left' ? 'Izquierda' : 'Derecha'}

} - {form.signatureStyle === 'qr' &&

Fondo: {form.qrBackground === 'transparent' ? 'Transparente' : 'Suave'}

} - {form.signatureStyle === 'qr' &&

Borde: {form.qrBorder === 'none' ? 'Sin borde' : 'Con borde'}

}

Página: {(sigPlacement?.page ?? 0) + 1}

+ + {showAdvancedOptions && ( + <> +

Razón: {form.reason}

+ {form.location &&

Ubicación: {form.location}

} +

Estilo visual: {form.signatureStyle}

+ {form.signatureStyle === 'qr' &&

Posición QR: {form.qrPosition === 'left' ? 'Izquierda' : 'Derecha'}

} + {form.signatureStyle === 'qr' &&

Fondo: {form.qrBackground === 'transparent' ? 'Transparente' : 'Suave'}

} + {form.signatureStyle === 'qr' &&

Borde: {form.qrBorder === 'none' ? 'Sin borde' : 'Con borde'}

} + + )}