Validaciones mandatorias — Sección 8 — IDs concretos
@@ -6,3 +6,7 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key-publica>
|
|||||||
|
|
||||||
# NUNCA agregar SUPABASE_SERVICE_ROLE_KEY como variable NEXT_PUBLIC_ ni en el cliente
|
# NUNCA agregar SUPABASE_SERVICE_ROLE_KEY como variable NEXT_PUBLIC_ ni en el cliente
|
||||||
# La service_role bypasa RLS — solo para Edge Functions / backend server-side
|
# La service_role bypasa RLS — solo para Edge Functions / backend server-side
|
||||||
|
|
||||||
|
# IP hash — variable server-only (NUNCA NEXT_PUBLIC_)
|
||||||
|
# Usada para deduplicación anónima. Generá un string aleatorio largo.
|
||||||
|
IP_HASH_SALT=
|
||||||
|
|||||||
109
app/actions/submit-survey.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
'use server'
|
||||||
|
import { headers } from 'next/headers'
|
||||||
|
import { createHash, randomUUID } from 'crypto'
|
||||||
|
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
|
||||||
|
|
||||||
|
export type SubmitResult =
|
||||||
|
| { success: true }
|
||||||
|
| { success: false; error: string }
|
||||||
|
|
||||||
|
export async function submitSurvey(payload: {
|
||||||
|
surveyId: string
|
||||||
|
answers: Record<string, unknown>
|
||||||
|
questionMap: Record<string, string> // código → question_id UUID
|
||||||
|
consentOperativo: boolean
|
||||||
|
consentMacroN1: boolean
|
||||||
|
}): Promise<SubmitResult> {
|
||||||
|
// 1. ip_hash: server-only, nunca en texto plano
|
||||||
|
const headersList = await headers()
|
||||||
|
const rawIp =
|
||||||
|
headersList.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'
|
||||||
|
const salt = process.env.IP_HASH_SALT ?? ''
|
||||||
|
const ipHash = createHash('sha256').update(rawIp + salt).digest('hex')
|
||||||
|
|
||||||
|
// 2. Cliente Supabase con anon key (RLS policies permiten INSERT a anon)
|
||||||
|
// NUNCA usar service_role — el anon key respeta RLS
|
||||||
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? ''
|
||||||
|
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ?? ''
|
||||||
|
const supabase = createSupabaseClient(supabaseUrl, supabaseAnonKey)
|
||||||
|
|
||||||
|
// 3. Leer survey para obtener org_id y consent_version_id
|
||||||
|
const { data: survey, error: sErr } = await supabase
|
||||||
|
.from('surveys')
|
||||||
|
.select('org_id, consent_version_id')
|
||||||
|
.eq('id', payload.surveyId)
|
||||||
|
.single()
|
||||||
|
|
||||||
|
if (sErr || !survey) return { success: false, error: 'survey_not_found' }
|
||||||
|
|
||||||
|
// 4. Pre-generar UUIDs server-side para evitar .select().single() post-INSERT.
|
||||||
|
//
|
||||||
|
// DIAGNÓSTICO: el Supabase JS client usa RETURNING * en .select().single(), lo que
|
||||||
|
// requiere SELECT policy para anon en consent_records/responses. Esa policy no existe
|
||||||
|
// (correcto — anon no debe leer consent_records de otros respondentes).
|
||||||
|
// Solución: pre-generar UUIDs con randomUUID() y NO hacer SELECT after INSERT.
|
||||||
|
const consentId = randomUUID()
|
||||||
|
const responseId = randomUUID()
|
||||||
|
|
||||||
|
// 5. INSERT consent_record (inmutable, ADR-003)
|
||||||
|
// Sin .select() para no activar RETURNING y evitar el error RLS 42501.
|
||||||
|
const { error: cErr } = await supabase
|
||||||
|
.from('consent_records')
|
||||||
|
.insert({
|
||||||
|
id: consentId,
|
||||||
|
consent_version_id: survey.consent_version_id,
|
||||||
|
granted_scopes: {
|
||||||
|
operativo: payload.consentOperativo,
|
||||||
|
macro_n1: payload.consentMacroN1,
|
||||||
|
},
|
||||||
|
granted_at: new Date().toISOString(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (cErr) return { success: false, error: `consent_insert_failed: ${cErr.message}` }
|
||||||
|
|
||||||
|
// 6. Extraer qi_* de las respuestas
|
||||||
|
const qi_age_bucket =
|
||||||
|
typeof payload.answers['A5'] === 'string' ? payload.answers['A5'] : null
|
||||||
|
const qi_sector =
|
||||||
|
typeof payload.answers['A4'] === 'string' ? payload.answers['A4'] : null
|
||||||
|
|
||||||
|
// 7. INSERT response (respondent_id=null — encuesta anónima, regla 2 CLAUDE.md)
|
||||||
|
const { error: rErr } = await supabase
|
||||||
|
.from('responses')
|
||||||
|
.insert({
|
||||||
|
id: responseId,
|
||||||
|
survey_id: payload.surveyId,
|
||||||
|
company_id: survey.org_id,
|
||||||
|
respondent_id: null,
|
||||||
|
ip_hash: ipHash,
|
||||||
|
consent_record_id: consentId,
|
||||||
|
qi_age_bucket: qi_age_bucket || null,
|
||||||
|
qi_sector: qi_sector || null,
|
||||||
|
qi_zone: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (rErr) return { success: false, error: `response_insert_failed: ${rErr.message}` }
|
||||||
|
|
||||||
|
// 8. INSERT answers — una fila por pregunta respondida
|
||||||
|
const answerRows = Object.entries(payload.answers)
|
||||||
|
.map(([code, value]) => ({
|
||||||
|
response_id: responseId,
|
||||||
|
question_id: payload.questionMap[code],
|
||||||
|
value,
|
||||||
|
}))
|
||||||
|
.filter(
|
||||||
|
(row) =>
|
||||||
|
row.question_id &&
|
||||||
|
row.value !== null &&
|
||||||
|
row.value !== undefined &&
|
||||||
|
row.value !== '' &&
|
||||||
|
!(Array.isArray(row.value) && row.value.length === 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (answerRows.length > 0) {
|
||||||
|
const { error: aErr } = await supabase.from('answers').insert(answerRows)
|
||||||
|
if (aErr) return { success: false, error: `answers_insert_failed: ${aErr.message}` }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
}
|
||||||
@@ -398,6 +398,61 @@ body {
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Geo select widget ── */
|
||||||
|
.geo-select-wrapper { display: flex; flex-direction: column; gap: 16px; }
|
||||||
|
.geo-select-group { display: flex; flex-direction: column; gap: 8px; }
|
||||||
|
.geo-select {
|
||||||
|
display: block; width: 100%;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1.5px solid var(--color-border); border-radius: var(--radius);
|
||||||
|
font-size: 1rem; font-family: inherit; background: var(--color-surface);
|
||||||
|
color: var(--color-text); cursor: pointer; appearance: auto;
|
||||||
|
transition: border-color 0.15s;
|
||||||
|
}
|
||||||
|
.geo-select:focus { outline: none; border-color: var(--color-border-focus); box-shadow: 0 0 0 3px rgba(37,99,235,0.15); }
|
||||||
|
.geo-select-disabled { opacity: 0.5; cursor: not-allowed; background: #f3f4f6; }
|
||||||
|
.geo-label-disabled { color: var(--color-text-muted); }
|
||||||
|
.geo-disabled-hint { font-size: 0.8125rem; font-weight: 400; color: var(--color-text-muted); }
|
||||||
|
|
||||||
|
/* ── Brand header ── */
|
||||||
|
.brand-header {
|
||||||
|
background: var(--color-primary-light); border-left: 4px solid var(--color-primary);
|
||||||
|
border-radius: 0 var(--radius) var(--radius) 0;
|
||||||
|
padding: 10px 14px; margin: 16px 0 0;
|
||||||
|
}
|
||||||
|
.brand-text { margin: 0; font-size: 0.875rem; color: var(--color-primary-hover); line-height: 1.5; }
|
||||||
|
|
||||||
|
/* ── Consent screen ── */
|
||||||
|
.consent-container { max-width: 720px; margin: 0 auto; padding: 32px 16px 80px; }
|
||||||
|
.consent-title { font-size: 1.5rem; font-weight: 700; margin: 0 0 24px; }
|
||||||
|
.consent-section { margin-bottom: 24px; }
|
||||||
|
.consent-section-title { font-size: 1.0625rem; font-weight: 700; margin: 0 0 10px; }
|
||||||
|
.consent-list { margin: 8px 0 0; padding-left: 20px; line-height: 1.7; display: flex; flex-direction: column; gap: 8px; }
|
||||||
|
.consent-anon-box {
|
||||||
|
background: var(--color-sensitive); border: 1px solid var(--color-sensitive-border);
|
||||||
|
border-radius: var(--radius); padding: 14px 16px; margin-bottom: 24px;
|
||||||
|
font-size: 0.9375rem; line-height: 1.6;
|
||||||
|
}
|
||||||
|
.consent-checkboxes { margin-bottom: 28px; display: flex; flex-direction: column; gap: 14px; }
|
||||||
|
.consent-checkbox-label {
|
||||||
|
display: flex; align-items: flex-start; gap: 12px;
|
||||||
|
padding: 14px 16px; border: 1.5px solid var(--color-border); border-radius: var(--radius);
|
||||||
|
cursor: pointer; transition: border-color 0.15s, background 0.15s; line-height: 1.5;
|
||||||
|
}
|
||||||
|
.consent-checkbox-label:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-light); }
|
||||||
|
.consent-checkbox-input { width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; accent-color: var(--color-primary); cursor: pointer; }
|
||||||
|
.consent-checkbox-text { flex: 1; }
|
||||||
|
.consent-required-badge { display: inline-block; font-size: 0.75rem; font-weight: 600; color: var(--color-primary); background: var(--color-primary-light); padding: 1px 6px; border-radius: 4px; }
|
||||||
|
.consent-optional-badge { display: inline-block; font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); background: #f3f4f6; padding: 1px 6px; border-radius: 4px; }
|
||||||
|
.consent-footer { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
|
||||||
|
.consent-required-hint { margin: 0; font-size: 0.875rem; color: var(--color-text-muted); }
|
||||||
|
.btn-disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
|
||||||
|
/* ── Thank you / error screens ── */
|
||||||
|
.thank-you-container, .error-container { max-width: 560px; margin: 80px auto; padding: 0 16px; }
|
||||||
|
.thank-you-title, .error-title { font-size: 1.5rem; font-weight: 700; margin: 0 0 16px; }
|
||||||
|
.thank-you-body { color: var(--color-text-muted); line-height: 1.7; margin: 0 0 12px; }
|
||||||
|
|
||||||
/* ── No survey state ── */
|
/* ── No survey state ── */
|
||||||
.no-survey {
|
.no-survey {
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
|
|||||||
50
app/page.tsx
@@ -1,21 +1,27 @@
|
|||||||
import { createClient } from '@/lib/supabase'
|
import { createClient } from '@/lib/supabase'
|
||||||
import type { Question, Survey } from '@/lib/types'
|
import type { BrandConfig, Question, Survey } from '@/lib/types'
|
||||||
import { SurveyForm } from '@/components/survey-form'
|
import { SurveyForm } from '@/components/survey-form'
|
||||||
|
|
||||||
// Force dynamic rendering — page fetches from Supabase at request time.
|
// Force dynamic rendering — page fetches from Supabase at request time.
|
||||||
// Never statically generated: credentials live in .env.local (runtime only).
|
|
||||||
export const dynamic = 'force-dynamic'
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
// Server Component — fetches survey with anon key; RLS ensures only status='live' is returned.
|
// In Next.js 15, searchParams is a Promise and must be awaited.
|
||||||
export default async function Page() {
|
interface PageProps {
|
||||||
|
searchParams: Promise<{ s?: string }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({ searchParams }: PageProps) {
|
||||||
|
const { s: surveyId } = await searchParams
|
||||||
const supabase = createClient()
|
const supabase = createClient()
|
||||||
|
|
||||||
// 1. Fetch the live survey
|
// 1. Fetch survey — by ?s=UUID if provided, otherwise first live survey
|
||||||
const { data: surveyRow, error: surveyError } = await supabase
|
const surveyQuery = supabase
|
||||||
.from('surveys')
|
.from('surveys')
|
||||||
.select('id, title, status, is_anonymous, k_threshold')
|
.select('id, org_id, title, status, is_anonymous, k_threshold, consent_version_id, brand_config')
|
||||||
.eq('status', 'live')
|
|
||||||
.maybeSingle()
|
const { data: surveyRow, error: surveyError } = surveyId
|
||||||
|
? await surveyQuery.eq('id', surveyId).maybeSingle()
|
||||||
|
: await surveyQuery.eq('status', 'live').maybeSingle()
|
||||||
|
|
||||||
if (surveyError) {
|
if (surveyError) {
|
||||||
return (
|
return (
|
||||||
@@ -32,10 +38,11 @@ export default async function Page() {
|
|||||||
<div className="no-survey" role="main">
|
<div className="no-survey" role="main">
|
||||||
<h1 className="no-survey-title">No hay encuesta activa</h1>
|
<h1 className="no-survey-title">No hay encuesta activa</h1>
|
||||||
<p>
|
<p>
|
||||||
Para ver el formulario, la encuesta debe estar en estado <code>live</code>.
|
Para ver el formulario, la encuesta debe estar en estado <code>live</code>,
|
||||||
|
o pasá el UUID por parámetro: <code>?s=UUID</code>.
|
||||||
</p>
|
</p>
|
||||||
<pre className="no-survey-hint">
|
<pre className="no-survey-hint">
|
||||||
{`-- Activar la encuesta en Supabase Cloud:\nUPDATE surveys\nSET status = 'live'\nWHERE id = '30000000-0000-0000-0000-000000000001';`}
|
{`-- Activar en Supabase Cloud:\nUPDATE surveys SET status = 'live'\nWHERE id = '30000000-0000-0000-0000-000000000001';`}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -61,20 +68,19 @@ export default async function Page() {
|
|||||||
|
|
||||||
const questions = questionRows as Question[]
|
const questions = questionRows as Question[]
|
||||||
|
|
||||||
// 3. Log question count for validation (visible in server logs and browser Network tab)
|
console.log(`[2B] Survey loaded: id=${surveyRow.id} | questions=${questions.length}`)
|
||||||
console.log(
|
|
||||||
`[2A] Survey loaded: id=${surveyRow.id} | questions=${questions.length}`
|
|
||||||
)
|
|
||||||
|
|
||||||
const survey: Survey = {
|
const survey: Survey = {
|
||||||
...(surveyRow as Omit<Survey, 'questions'>),
|
id: surveyRow.id,
|
||||||
|
org_id: surveyRow.org_id,
|
||||||
|
title: surveyRow.title,
|
||||||
|
status: surveyRow.status,
|
||||||
|
is_anonymous: surveyRow.is_anonymous,
|
||||||
|
k_threshold: surveyRow.k_threshold,
|
||||||
|
consent_version_id: surveyRow.consent_version_id,
|
||||||
|
brand_config: (surveyRow.brand_config as BrandConfig) ?? null,
|
||||||
questions,
|
questions,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <SurveyForm survey={survey} questions={questions} />
|
||||||
<SurveyForm
|
|
||||||
survey={survey}
|
|
||||||
questions={questions}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
assets/.DS_Store
vendored
Normal file
BIN
assets/fundacion/.DS_Store
vendored
Normal file
BIN
assets/fundacion/ISOLOGO HORIZONATAL-FS.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/fundacion/ISOLOGO VERTICAL TAGLINE-FS-28.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/fundacion/ISOLOGO VERTICAL-FS.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/fundacion/ISOTIPO_FS.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/fundacion/LOGOTIPO-FS.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/fundacion/Versión Horiz_Isologotipo FS-17.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
380
assets/fundacion/Versión Horiz_Isologotipo FS-17.svg
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="535.614px" height="308.44px" viewBox="0 0 535.614 308.44" enable-background="new 0 0 535.614 308.44"
|
||||||
|
xml:space="preserve">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#129539" d="M181.184,99.452c-0.34-0.962-0.875-1.782-1.596-2.409
|
||||||
|
c-0.729-0.643-1.628-1.059-2.608-1.183c-2.093-0.275-4.58,0.708-6.829,3.731c-1.76,1.805-4.482,5.509-7.164,9.176
|
||||||
|
c-2.851,3.915-5.667,7.738-7.12,9.029c-0.727,0.664-1.556,0.967-2.206,0.945c-0.281-0.027-0.548-0.098-0.732-0.238h-0.021
|
||||||
|
c-0.165-0.14-0.303-0.323-0.4-0.588c-0.167-0.584-0.046-1.432,0.492-2.549c2.257-4.683,6.057-12.303,9.529-19.074
|
||||||
|
c2.979-5.827,5.676-11.001,6.939-13.166c2.279-3.803,2.374-7.205,1.248-9.457c-0.494-0.939-1.199-1.711-2.065-2.182
|
||||||
|
c-0.843-0.491-1.855-0.723-2.933-0.604c-2.441,0.232-5.228,2.177-7.482,6.47c-2.673,5.163-5.185,9.78-7.674,14.381
|
||||||
|
c-2.981,5.466-5.913,10.86-8.935,16.779c-0.521,0.815-1.193,1.426-1.828,1.701c-0.289,0.124-0.524,0.194-0.737,0.151
|
||||||
|
c-0.162-0.027-0.319-0.124-0.44-0.308c-0.259-0.324-0.421-0.913-0.421-1.831c-0.027-3.052,3.124-12.577,5.627-20.154
|
||||||
|
c1.037-3.191,1.971-6.021,2.536-7.933c0.891-3.116,2.374-8.484,3.521-12.945c1.032-3.937,1.828-7.177,1.828-7.625
|
||||||
|
c-0.021-2.23-0.516-3.916-1.291-5.114c-0.748-1.129-1.709-1.81-2.819-2.128c-1.075-0.34-2.252-0.286-3.391,0.043
|
||||||
|
c-1.512,0.47-2.962,1.432-4.094,2.787c-1.755,2.139-4.102,10.217-6.045,16.968l-0.608,2.058c-0.542,1.879-1.574,5.59-2.724,9.764
|
||||||
|
c-2.09,7.646-4.623,16.871-5.422,19.031c-0.373,1.053-1.01,1.798-1.685,2.149c-0.275,0.146-0.591,0.216-0.851,0.194
|
||||||
|
c-0.232-0.027-0.438-0.124-0.632-0.308c-0.395-0.378-0.702-1.097-0.748-2.252c-0.327-5.654,0.256-13.118,0.845-20.506
|
||||||
|
c0.491-6.194,0.958-12.313,0.915-17.319c0.235-3.32-0.842-5.643-2.468-6.934c-0.775-0.632-1.685-1.01-2.646-1.156
|
||||||
|
c-0.942-0.135-1.928-0.021-2.86,0.324c-2.068,0.756-3.896,2.685-4.601,5.676c-1.269,5.455-1.925,13.686-2.533,21.311
|
||||||
|
c-0.588,7.463-1.15,14.332-2.16,17.222c-0.448,1.215-1.199,3.24-2.136,4.854c-0.821,1.383-1.736,2.506-2.536,2.35
|
||||||
|
c-2.533-0.48-2.859-2.587-3.14-4.396c-0.046-0.389-0.119-0.793-0.189-1.16c-0.235-1.912-0.603-3.904-1.078-5.801
|
||||||
|
c-0.448-1.922-1.007-3.774-1.593-5.4c-1.064-2.835-3.005-5.551-5.239-7.344c-1.08-0.838-2.249-1.496-3.416-1.831
|
||||||
|
c-1.226-0.318-2.468-0.318-3.664,0.118c-1.013,0.373-1.974,1.086-2.841,2.166c-2.136,2.674-0.632,6.658,1.288,11.849
|
||||||
|
c1.95,5.228,4.393,11.751,3.832,19.042c-0.127,1.522-0.24,3.057-0.383,4.53c-0.762,9.202-1.38,17.33-0.148,26.965
|
||||||
|
c1.045,0.34,2.092,0.681,3.181,1.074c0,0-0.256-0.967,1.248-11.789c2.787-20.073,27.423-29.054,45.787-18.923
|
||||||
|
c12.418,6.854,17.333,18.696,18.124,31.619c3.98-6.604,6.618-12.285,7.59-15.429c0.443-1.501,2.959-5.396,6-9.808
|
||||||
|
c4.577-6.62,10.398-14.321,12.461-16.8C181.532,104.62,181.951,101.683,181.184,99.452z"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#163F75" d="M153.942,161.811c-0.454,0-0.856,0-1.302,0
|
||||||
|
c-0.934,8.527-3.151,17-5.765,24.361c-8.868,25.03-8.111,45.039-45.396,37.861c-11.679-2.246-24.604-4.73-36.032-8.883
|
||||||
|
c14.938,42.295,79.458,45.109,90.397,6.248C159.669,207.789,161.961,181.332,153.942,161.811z"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#E00914" d="M91.254,160.644c3.381,2.273-0.47-4.86,2.627-17.275
|
||||||
|
c4.412-17.567,20.135-29.179,36.528-20.128c21.699,11.968,17.783,40.968,10.744,60.857c-7.925,22.357-7.272,40.238-40.563,33.833
|
||||||
|
c-26.197-5.065-59.521-11.405-60.733-39.601C39.311,165.963,57.051,133.426,91.254,160.644L91.254,160.644z"/>
|
||||||
|
<path fill="#E00914" d="M199.191,221.652c4.323,0,7.555-1.291,9.834-3.916c1.733-1.943,2.6-4.504,2.6-7.604
|
||||||
|
c0-3.37-1.288-6.658-3.823-9.872c-1.167-1.458-2.487-2.884-3.848-4.271c-3.378-3.327-5.77-6.118-7.131-8.489
|
||||||
|
c-1.547-2.582-2.301-5.298-2.301-8.182c0-3.041,0.548-5.471,1.577-7.302c1.245-2.208,3.07-3.326,5.422-3.326
|
||||||
|
c3.256,0,5.365,1.998,6.421,5.908c0.467,1.755,0.678,3.71,0.678,5.789c0,2.819-0.278,5.54-0.842,8.235
|
||||||
|
c-0.07,0.384-0.116,0.751-0.116,1.129c0,1.388,0.681,2.09,2.063,2.09c1.528,0,2.605-1.388,3.243-4.175
|
||||||
|
c0.488-2.024,0.721-4.46,0.721-7.279c0-11.276-4.404-16.888-13.25-16.888c-4.226,0-7.625,1.167-10.158,3.56
|
||||||
|
c-1.312,1.22-2.344,2.689-3.075,4.438c-1.007,2.463-1.526,5.282-1.526,8.377c0,4.525,1.196,8.678,3.621,12.383
|
||||||
|
c1.658,2.581,4.072,5.465,7.345,8.635c1.142,1.178,2.228,2.279,3.227,3.381c2.182,2.42,3.238,4.672,3.238,6.756
|
||||||
|
c0,3.262-1.48,4.903-4.429,4.903c-2.651,0-4.366-1.388-5.076-4.196c-0.33-1.145-0.486-2.327-0.486-3.45
|
||||||
|
c0-1.858-0.751-2.792-2.252-2.792c-1.645,0-2.671,1.571-2.671,3.64c0,3.656,0.772,6.54,2.387,8.646
|
||||||
|
C192.557,220.361,195.419,221.652,199.191,221.652L199.191,221.652z M234.038,216.235c-3.008,0-5.238-1.755-6.71-5.249
|
||||||
|
c-1.296-3.121-1.947-7.345-1.947-12.691c0-10.963,3.138-16.428,9.402-16.428c2.889,0,4.95,1.782,6.267,5.373
|
||||||
|
c1.013,2.781,1.499,6.243,1.499,10.461c0,5.093-0.635,9.321-1.877,12.669C239.192,214.291,236.989,216.235,234.038,216.235
|
||||||
|
L234.038,216.235z M231.667,221.587c5.819,0,10.134-2.278,12.853-6.848c2.39-4.062,3.591-9.612,3.591-16.703
|
||||||
|
c0-5.563-0.872-10.164-2.632-13.749c-2.417-4.926-6.189-7.394-11.395-7.394c-6.011,0-10.487,2.273-13.425,6.874
|
||||||
|
c-2.603,3.991-3.918,9.451-3.918,16.348c0,5.897,1.034,10.66,3.124,14.365C222.519,219.238,226.48,221.587,231.667,221.587
|
||||||
|
L231.667,221.587z M263.008,221.728c0.889,0,1.974-0.141,3.211-0.491c1.218-0.33,2.233-0.768,2.983-1.41
|
||||||
|
c0.554-0.47,0.861-0.988,0.861-1.62c0-0.794-0.486-1.198-1.499-1.198c-0.324,0-0.821,0.075-1.477,0.265
|
||||||
|
c-0.426,0.118-0.918,0.184-1.474,0.184c-1.855,0-2.187-1.523-2.187-9.219v-38.548c0-1.62-0.284-2.9-0.77-3.915
|
||||||
|
c-0.732-1.523-2.001-2.274-3.751-2.274c-3.103,0-4.137,1.707-4.137,6.497v33.126c0,2.933,0.076,5.697,0.262,8.214
|
||||||
|
c0.21,2.717,0.772,4.925,1.663,6.681C257.958,220.485,260.049,221.728,263.008,221.728L263.008,221.728z M279.279,174.36
|
||||||
|
c1.653,0,2.825-0.61,3.594-1.755c0.545-0.777,0.805-1.717,0.805-2.797c0-1.193-0.4-2.317-1.205-3.327
|
||||||
|
c-0.767-1.01-1.831-1.534-3.122-1.534c-2.53,0-4.331,2.215-4.331,5.331C275.021,173,276.447,174.36,279.279,174.36L279.279,174.36z
|
||||||
|
M279.123,221.652c3.019,0,4.556-2.08,4.556-6.238v-32.023c0-4.828-1.129-6.497-4.129-6.497c-2.983,0-4.528,2.16-4.528,6.199v32.02
|
||||||
|
c0,1.102,0.089,2.133,0.232,3.143C275.583,220.556,276.849,221.652,279.123,221.652L279.123,221.652z M309.905,193.721
|
||||||
|
c0,2.9-0.237,5.936-0.683,9.073c-0.421,3.1-1.08,5.746-1.947,7.884c-1.571,3.965-3.542,5.936-5.935,5.936
|
||||||
|
c-3.029,0.162-3.988-6.729-3.988-14.009c0-4.963,1.482-20.43,8.587-20.43c1.949,0,3.138,0.47,3.634,1.447
|
||||||
|
c0.211,0.476,0.332,1.037,0.332,1.642V193.721z M318.535,169.997c0-3.208-0.138-6.497-4.131-6.497c-3.467,0-4.499,3.009-4.499,6.189
|
||||||
|
v7.458c0,0.572-0.078,0.875-0.259,0.875c-0.189,0-0.5-0.119-0.867-0.303c-1.083-0.572-2.279-0.826-3.521-0.826
|
||||||
|
c-4.698,0-8.352,2.673-11.006,8.073c-2.481,5.109-3.729,11.806-3.729,20.035c0,8.83,3.238,16.796,9.602,16.65
|
||||||
|
c3.375,0,6.186-1.756,8.435-5.229c0.662-1.068,1.04-1.642,1.153-1.642s0.191,0.232,0.191,0.632c0,3.191,1.032,6.238,4.499,6.238
|
||||||
|
c3.994,0,4.131-3.278,4.131-6.54V169.997z M348.777,221.652c3.964,0.075,4.061-3.322,4.129-6.54v-31.722
|
||||||
|
c-0.068-3.139-0.165-6.563-4.129-6.497c-1.385,0-2.443,0.427-3.075,1.226c-0.208,0.281-0.462,0.416-0.815,0.416
|
||||||
|
c-0.241,0-0.6-0.107-0.97-0.329c-1.501-0.864-2.951-1.313-4.355-1.313c-4.72,0-8.387,2.673-11.03,8.073
|
||||||
|
c-2.484,5.109-3.729,11.806-3.729,20.035c0,8.83,3.265,16.796,9.597,16.65c3.794,0,6.826-2.08,9.121-6.26
|
||||||
|
c0.259-0.496,0.448-0.729,0.567-0.729c0.116,0,0.167,0.275,0.167,0.75C344.254,218.605,345.299,221.652,348.777,221.652
|
||||||
|
L348.777,221.652z M335.616,216.613c-3.027,0.162-3.991-6.729-3.991-14.009c0-4.963,1.477-20.43,8.586-20.43
|
||||||
|
c2.7,0,4.042,0.967,4.042,2.911v10.342c0,1.879-0.216,4.336-0.664,7.366c-0.467,3.029-1.128,5.681-2.042,7.884
|
||||||
|
C339.999,214.643,338.006,216.613,335.616,216.613L335.616,216.613z M365.996,221.652c3.027,0,4.525-2.08,4.525-6.238v-9.996
|
||||||
|
c0-6.988,0.889-12.664,2.649-17c1.763-4.391,3.78-6.551,5.986-6.551c0.651,0,1.212,0.211,1.712,0.653
|
||||||
|
c0.632,0.572,1.24,0.87,1.828,0.87c1.62,0,2.887-1.664,2.887-3.44c0-1.977-2.322-3.057-5.16-3.057c-3.705,0-6.731,2.068-9.081,6.199
|
||||||
|
c-0.259,0.486-0.489,0.751-0.629,0.751c-0.122,0-0.192-0.265-0.192-0.805c0-4.104-1.499-6.146-4.525-6.146
|
||||||
|
c-3.894,0-4.128,3.262-4.128,6.448v31.771c0,1.069,0.097,2.133,0.235,3.143C362.429,220.556,363.739,221.652,365.996,221.652
|
||||||
|
L365.996,221.652z M393.254,174.36c1.645,0,2.841-0.61,3.616-1.755c0.516-0.777,0.799-1.717,0.799-2.797
|
||||||
|
c0-1.193-0.427-2.317-1.207-3.327c-0.789-1.01-1.823-1.534-3.138-1.534c-2.533,0-4.315,2.215-4.315,5.331
|
||||||
|
C389.01,173,390.414,174.36,393.254,174.36L393.254,174.36z M393.12,221.652c2.997,0,4.55-2.08,4.55-6.238v-32.023
|
||||||
|
c0-4.828-1.134-6.497-4.137-6.497c-2.997,0-4.523,2.16-4.523,6.199v32.02c0,1.102,0.067,2.133,0.229,3.143
|
||||||
|
C389.571,220.556,390.838,221.652,393.12,221.652L393.12,221.652z M423.867,193.721c0,2.9-0.205,5.936-0.656,9.073
|
||||||
|
c-0.418,3.1-1.077,5.746-1.95,7.884c-1.566,3.965-3.534,5.936-5.951,5.936c-3.029,0.162-3.999-6.729-3.999-14.009
|
||||||
|
c0-4.963,1.51-20.43,8.619-20.43c1.917,0,3.122,0.47,3.613,1.447c0.235,0.476,0.324,1.037,0.324,1.642V193.721z M432.529,169.997
|
||||||
|
c0-3.208-0.167-6.497-4.128-6.497c-3.473,0-4.534,3.009-4.534,6.189v7.458c0,0.572-0.043,0.875-0.254,0.875
|
||||||
|
c-0.184,0-0.467-0.119-0.867-0.303c-1.083-0.572-2.255-0.826-3.494-0.826c-4.72,0-8.378,2.673-11.003,8.073
|
||||||
|
c-2.511,5.109-3.731,11.806-3.731,20.035c0,8.83,3.237,16.796,9.575,16.65c3.4,0,6.187-1.756,8.444-5.229
|
||||||
|
c0.675-1.068,1.053-1.642,1.169-1.642c0.119,0,0.162,0.232,0.162,0.632c0,3.191,1.061,6.238,4.534,6.238
|
||||||
|
c3.961,0,4.128-3.278,4.128-6.54V169.997z M462.744,221.652c3.985,0.075,4.058-3.322,4.15-6.54v-31.722
|
||||||
|
c-0.092-3.139-0.165-6.563-4.15-6.497c-1.364,0-2.417,0.427-3.049,1.226c-0.21,0.281-0.494,0.416-0.823,0.416
|
||||||
|
c-0.257,0-0.607-0.107-0.961-0.329c-1.501-0.864-2.957-1.313-4.391-1.313c-4.714,0-8.373,2.673-10.995,8.073
|
||||||
|
c-2.492,5.109-3.737,11.806-3.737,20.035c0,8.83,3.24,16.796,9.578,16.65c3.82,0,6.848-2.08,9.121-6.26
|
||||||
|
c0.259-0.496,0.454-0.729,0.567-0.729c0.119,0,0.178,0.275,0.178,0.75C458.232,218.605,459.271,221.652,462.744,221.652
|
||||||
|
L462.744,221.652z M449.602,216.613c-3.024,0.162-4.001-6.729-4.001-14.009c0-4.963,1.499-20.43,8.605-20.43
|
||||||
|
c2.697,0,4.026,0.967,4.026,2.911v10.342c0,1.879-0.203,4.336-0.648,7.366c-0.467,3.029-1.131,5.681-2.044,7.884
|
||||||
|
C453.974,214.643,452,216.613,449.602,216.613L449.602,216.613z M492.913,193.721c0,2.9-0.208,5.936-0.656,9.073
|
||||||
|
c-0.427,3.1-1.08,5.746-1.95,7.884c-1.563,3.965-3.54,5.936-5.935,5.936c-3.027,0.162-4.013-6.729-4.013-14.009
|
||||||
|
c0-4.963,1.507-20.43,8.614-20.43c1.944,0,3.143,0.47,3.616,1.447c0.232,0.476,0.324,1.037,0.324,1.642V193.721z M501.573,169.997
|
||||||
|
c0-3.208-0.148-6.497-4.137-6.497c-3.461,0-4.523,3.009-4.523,6.189v7.458c0,0.572-0.048,0.875-0.237,0.875
|
||||||
|
c-0.203,0-0.492-0.119-0.867-0.303c-1.102-0.572-2.274-0.826-3.519-0.826c-4.717,0-8.373,2.673-11.003,8.073
|
||||||
|
c-2.484,5.109-3.729,11.806-3.729,20.035c0,8.83,3.24,16.796,9.57,16.65c3.405,0,6.224-1.756,8.449-5.229
|
||||||
|
c0.681-1.068,1.053-1.642,1.169-1.642c0.119,0,0.167,0.232,0.167,0.632c0,3.191,1.062,6.238,4.523,6.238
|
||||||
|
c3.988,0,4.137-3.278,4.137-6.54V169.997z"/>
|
||||||
|
<path fill="#2A2A2B" d="M190.7,230.309v11.546h-1.399v-11.546H190.7z M194.639,236.648v5.206h-1.334v-8.651h1.288v1.361h0.122
|
||||||
|
c0.213-0.454,0.516-0.805,0.913-1.086c0.424-0.265,0.964-0.395,1.62-0.395c0.864,0,1.574,0.275,2.111,0.816
|
||||||
|
c0.54,0.518,0.821,1.365,0.821,2.462v5.492h-1.336v-5.4c0-0.702-0.184-1.215-0.54-1.587c-0.348-0.4-0.824-0.589-1.458-0.589
|
||||||
|
c-0.632,0-1.145,0.21-1.569,0.637C194.853,235.314,194.639,235.903,194.639,236.648L194.639,236.648z M206.377,233.203v1.123h-1.855
|
||||||
|
v5.045c0,0.399,0.07,0.652,0.165,0.842c0.122,0.194,0.256,0.335,0.427,0.378c0.181,0.07,0.367,0.098,0.556,0.098
|
||||||
|
c0.138,0,0.281,0,0.375-0.027c0.092-0.026,0.162-0.026,0.213-0.043l0.281,1.188c-0.097,0.048-0.211,0.069-0.381,0.118
|
||||||
|
c-0.159,0.021-0.373,0.043-0.629,0.043c-0.378,0-0.721-0.064-1.099-0.237c-0.356-0.156-0.656-0.41-0.894-0.751
|
||||||
|
c-0.24-0.318-0.351-0.739-0.351-1.231v-5.422h-1.293v-1.123h1.293v-2.073h1.337v2.073H206.377z M211.915,242.044
|
||||||
|
c-0.826,0-1.55-0.189-2.144-0.557c-0.607-0.389-1.075-0.896-1.41-1.556c-0.324-0.675-0.486-1.457-0.486-2.344
|
||||||
|
c0-0.863,0.162-1.663,0.486-2.349c0.335-0.675,0.781-1.199,1.364-1.566c0.594-0.41,1.267-0.589,2.071-0.589
|
||||||
|
c0.442,0,0.885,0.07,1.336,0.232c0.418,0.141,0.845,0.4,1.199,0.724c0.346,0.33,0.653,0.772,0.861,1.34
|
||||||
|
c0.208,0.545,0.308,1.22,0.308,2.041v0.562h-6.284c0.046,0.918,0.303,1.62,0.789,2.111c0.494,0.497,1.134,0.751,1.909,0.751
|
||||||
|
c0.535,0,0.978-0.113,1.361-0.324c0.37-0.237,0.651-0.562,0.815-1.036l1.293,0.372c-0.216,0.664-0.61,1.172-1.218,1.583
|
||||||
|
C213.551,241.833,212.803,242.044,211.915,242.044L211.915,242.044z M209.217,236.838h4.95c0-0.734-0.219-1.334-0.665-1.831
|
||||||
|
c-0.416-0.47-0.982-0.729-1.706-0.729c-0.524,0-0.967,0.113-1.315,0.351c-0.375,0.238-0.688,0.567-0.894,0.939
|
||||||
|
C209.377,235.969,209.263,236.395,209.217,236.838L209.217,236.838z M217.54,241.854v-8.651h1.291v1.307h0.076
|
||||||
|
c0.154-0.416,0.435-0.767,0.861-1.053c0.427-0.254,0.87-0.395,1.41-0.395c0.089,0,0.208,0,0.351,0
|
||||||
|
c0.143,0.021,0.262,0.021,0.334,0.021v1.367c-0.021-0.033-0.143-0.033-0.311-0.06c-0.146-0.021-0.327-0.044-0.494-0.044
|
||||||
|
c-0.632,0-1.145,0.189-1.569,0.589c-0.429,0.378-0.604,0.87-0.604,1.458v5.46H217.54z M230.797,233.203l-3.189,8.651h-1.363
|
||||||
|
l-3.219-8.651h1.455l2.393,6.891h0.097l2.395-6.891H230.797z M235.857,242.044c-0.807,0-1.539-0.189-2.155-0.557
|
||||||
|
c-0.583-0.389-1.056-0.896-1.382-1.556c-0.33-0.675-0.491-1.457-0.491-2.344c0-0.863,0.162-1.663,0.491-2.349
|
||||||
|
c0.327-0.675,0.772-1.199,1.361-1.566c0.589-0.41,1.269-0.589,2.068-0.589c0.443,0,0.886,0.07,1.334,0.232
|
||||||
|
c0.416,0.141,0.848,0.4,1.193,0.724c0.354,0.33,0.665,0.772,0.87,1.34c0.21,0.545,0.305,1.22,0.305,2.041v0.562h-6.286
|
||||||
|
c0.046,0.918,0.302,1.62,0.796,2.111c0.492,0.497,1.129,0.751,1.896,0.751c0.545,0,0.988-0.113,1.364-0.324
|
||||||
|
c0.375-0.237,0.659-0.562,0.826-1.036l1.285,0.372c-0.216,0.664-0.607,1.172-1.215,1.583
|
||||||
|
C237.5,241.833,236.751,242.044,235.857,242.044L235.857,242.044z M233.166,236.838h4.952c0-0.734-0.21-1.334-0.664-1.831
|
||||||
|
c-0.419-0.47-1.007-0.729-1.704-0.729c-0.521,0-0.967,0.113-1.315,0.351c-0.375,0.238-0.686,0.567-0.891,0.939
|
||||||
|
C233.333,235.969,233.211,236.395,233.166,236.838L233.166,236.838z M242.83,236.648v5.206h-1.337v-8.651h1.293v1.361h0.089
|
||||||
|
c0.213-0.454,0.516-0.805,0.939-1.086c0.397-0.265,0.945-0.395,1.596-0.395c0.87,0,1.596,0.275,2.136,0.816
|
||||||
|
c0.535,0.518,0.793,1.365,0.793,2.462v5.492h-1.333v-5.4c0-0.702-0.162-1.215-0.516-1.587c-0.354-0.4-0.839-0.589-1.453-0.589
|
||||||
|
c-0.634,0-1.177,0.21-1.593,0.637C243.013,235.314,242.83,235.903,242.83,236.648L242.83,236.648z M254.303,242.044
|
||||||
|
c-0.821,0-1.526-0.189-2.117-0.578c-0.556-0.384-1.023-0.896-1.334-1.577c-0.327-0.68-0.467-1.452-0.467-2.301
|
||||||
|
c0-0.891,0.14-1.663,0.467-2.349c0.333-0.675,0.802-1.199,1.383-1.566c0.588-0.41,1.269-0.589,2.049-0.589
|
||||||
|
c0.607,0,1.14,0.119,1.636,0.352c0.492,0.205,0.889,0.535,1.199,0.935c0.324,0.399,0.519,0.896,0.581,1.437h-1.333
|
||||||
|
c-0.089-0.405-0.327-0.751-0.659-1.064c-0.346-0.291-0.815-0.464-1.404-0.464c-0.778,0-1.412,0.308-1.874,0.891
|
||||||
|
c-0.494,0.583-0.729,1.388-0.729,2.371c0,0.982,0.235,1.798,0.708,2.392c0.464,0.616,1.096,0.913,1.896,0.913
|
||||||
|
c0.513,0,0.964-0.135,1.336-0.394c0.378-0.287,0.613-0.638,0.727-1.129h1.333c-0.062,0.518-0.256,0.988-0.556,1.388
|
||||||
|
c-0.283,0.421-0.688,0.756-1.15,0.978C255.499,241.925,254.935,242.044,254.303,242.044L254.303,242.044z M259.652,241.854v-8.651
|
||||||
|
h1.312v8.651H259.652z M260.33,231.767c-0.281,0-0.494-0.092-0.678-0.28c-0.184-0.162-0.284-0.379-0.284-0.633
|
||||||
|
c0-0.253,0.1-0.469,0.284-0.637c0.184-0.184,0.397-0.248,0.678-0.248c0.256,0,0.472,0.064,0.664,0.248
|
||||||
|
c0.184,0.168,0.275,0.384,0.275,0.637c0,0.254-0.092,0.471-0.275,0.633C260.802,231.675,260.586,231.767,260.33,231.767
|
||||||
|
L260.33,231.767z M266.923,242.044c-0.775,0-1.453-0.189-2.039-0.557c-0.591-0.389-1.059-0.896-1.385-1.556
|
||||||
|
c-0.332-0.675-0.492-1.457-0.492-2.344c0-0.912,0.16-1.685,0.492-2.37c0.327-0.681,0.794-1.199,1.385-1.577
|
||||||
|
c0.586-0.378,1.264-0.557,2.039-0.557c0.772,0,1.477,0.179,2.065,0.557c0.589,0.378,1.029,0.896,1.364,1.577
|
||||||
|
c0.324,0.686,0.491,1.458,0.491,2.37c0,0.887-0.167,1.669-0.491,2.344c-0.335,0.659-0.775,1.167-1.364,1.556
|
||||||
|
C268.4,241.854,267.695,242.044,266.923,242.044L266.923,242.044z M266.923,240.845c0.588,0,1.077-0.156,1.477-0.438
|
||||||
|
c0.375-0.313,0.651-0.729,0.848-1.226c0.187-0.491,0.284-1.026,0.284-1.594c0-0.588-0.097-1.134-0.284-1.619
|
||||||
|
c-0.197-0.519-0.473-0.913-0.848-1.227c-0.4-0.291-0.889-0.464-1.477-0.464c-0.586,0-1.075,0.173-1.453,0.464
|
||||||
|
c-0.408,0.313-0.683,0.708-0.875,1.227c-0.187,0.485-0.256,1.031-0.256,1.619c0,0.567,0.07,1.103,0.256,1.594
|
||||||
|
c0.192,0.497,0.467,0.912,0.875,1.226C265.849,240.688,266.337,240.845,266.923,240.845L266.923,240.845z M266.313,232.031
|
||||||
|
l1.382-2.635h1.553l-1.763,2.635H266.313z M274.222,236.648v5.206h-1.342v-8.651h1.288v1.361h0.122
|
||||||
|
c0.189-0.454,0.491-0.805,0.918-1.086c0.424-0.265,0.937-0.395,1.596-0.395c0.889,0,1.593,0.275,2.128,0.816
|
||||||
|
c0.542,0.518,0.805,1.365,0.805,2.462v5.492h-1.318v-5.4c0-0.702-0.192-1.215-0.54-1.587c-0.356-0.4-0.848-0.589-1.453-0.589
|
||||||
|
c-0.629,0-1.172,0.21-1.569,0.637C274.427,235.314,274.222,235.903,274.222,236.648L274.222,236.648z M287.45,245.214
|
||||||
|
c-0.208,0-0.416,0-0.605-0.049c-0.17-0.021-0.283-0.07-0.359-0.092l0.329-1.177c0.492,0.118,0.894,0.118,1.223-0.027
|
||||||
|
c0.327-0.113,0.608-0.508,0.84-1.145l0.284-0.821l-3.191-8.7h1.431l2.398,6.891h0.089l2.4-6.891h1.423l-3.702,10.066
|
||||||
|
C289.51,244.576,288.671,245.214,287.45,245.214L287.45,245.214z M303.8,233.203v1.123h-1.917v7.528h-1.342v-7.528h-1.401v-1.123
|
||||||
|
h1.401v-1.199c0-0.491,0.122-0.912,0.351-1.242c0.238-0.329,0.516-0.566,0.894-0.729c0.375-0.189,0.775-0.265,1.196-0.265
|
||||||
|
c0.33,0,0.586,0.032,0.797,0.075c0.216,0.076,0.356,0.125,0.467,0.162l-0.392,1.156c-0.076-0.032-0.173-0.07-0.287-0.098
|
||||||
|
c-0.119-0.021-0.256-0.049-0.472-0.049c-0.416,0-0.748,0.092-0.935,0.33c-0.189,0.216-0.278,0.54-0.278,0.988v0.869H303.8z
|
||||||
|
M308.854,242.044c-0.802,0-1.488-0.189-2.071-0.557c-0.589-0.389-1.053-0.896-1.388-1.556c-0.324-0.675-0.486-1.457-0.486-2.344
|
||||||
|
c0-0.912,0.162-1.685,0.486-2.37c0.335-0.681,0.799-1.199,1.388-1.577c0.583-0.378,1.269-0.557,2.071-0.557
|
||||||
|
c0.767,0,1.445,0.179,2.031,0.557s1.056,0.896,1.385,1.577c0.334,0.686,0.497,1.458,0.497,2.37c0,0.887-0.162,1.669-0.497,2.344
|
||||||
|
c-0.33,0.659-0.799,1.167-1.385,1.556C310.299,241.854,309.622,242.044,308.854,242.044L308.854,242.044z M308.854,240.845
|
||||||
|
c0.575,0,1.072-0.156,1.445-0.438c0.378-0.313,0.653-0.729,0.842-1.226c0.194-0.491,0.286-1.026,0.286-1.594
|
||||||
|
c0-0.588-0.092-1.134-0.286-1.619c-0.189-0.519-0.464-0.913-0.842-1.227c-0.373-0.291-0.87-0.464-1.445-0.464
|
||||||
|
c-0.624,0-1.11,0.173-1.488,0.464c-0.37,0.313-0.659,0.708-0.84,1.227c-0.194,0.485-0.283,1.031-0.283,1.619
|
||||||
|
c0,0.567,0.089,1.103,0.283,1.594c0.181,0.497,0.47,0.912,0.84,1.226C307.745,240.688,308.231,240.845,308.854,240.845
|
||||||
|
L308.854,240.845z M314.782,241.854v-8.651h1.285v1.307h0.1c0.165-0.416,0.443-0.767,0.867-1.053
|
||||||
|
c0.396-0.254,0.864-0.395,1.385-0.395c0.095,0,0.211,0,0.375,0c0.135,0.021,0.262,0.021,0.33,0.021v1.367
|
||||||
|
c-0.049-0.033-0.143-0.033-0.305-0.06c-0.167-0.021-0.33-0.044-0.516-0.044c-0.632,0-1.15,0.189-1.55,0.589
|
||||||
|
c-0.421,0.378-0.634,0.87-0.634,1.458v5.46H314.782z M320.689,241.854v-8.651h1.299v1.361h0.113c0.195-0.471,0.473-0.821,0.87-1.086
|
||||||
|
s0.891-0.395,1.445-0.395c0.569,0,1.063,0.13,1.439,0.395s0.678,0.615,0.891,1.086h0.1c0.208-0.454,0.532-0.821,0.977-1.086
|
||||||
|
c0.448-0.265,0.988-0.395,1.604-0.395c0.767,0,1.404,0.249,1.896,0.734c0.494,0.481,0.746,1.237,0.746,2.242v5.794h-1.334v-5.794
|
||||||
|
c0-0.633-0.165-1.102-0.519-1.361c-0.351-0.281-0.767-0.421-1.239-0.421c-0.61,0-1.083,0.188-1.41,0.562
|
||||||
|
c-0.33,0.356-0.513,0.826-0.513,1.383v5.632h-1.336v-5.93c0-0.497-0.165-0.896-0.491-1.183c-0.308-0.291-0.735-0.464-1.223-0.464
|
||||||
|
c-0.356,0-0.681,0.092-0.988,0.286c-0.278,0.178-0.538,0.442-0.702,0.75c-0.189,0.33-0.286,0.702-0.286,1.14v5.4H320.689z
|
||||||
|
M337.044,242.065c-0.537,0-1.031-0.119-1.474-0.335c-0.454-0.173-0.821-0.48-1.083-0.886c-0.259-0.394-0.396-0.886-0.396-1.452
|
||||||
|
c0-0.492,0.121-0.887,0.308-1.193c0.184-0.309,0.443-0.567,0.772-0.729c0.332-0.189,0.699-0.303,1.104-0.399
|
||||||
|
c0.37-0.092,0.77-0.168,1.194-0.211c0.513-0.064,0.942-0.119,1.271-0.162c0.321-0.021,0.583-0.098,0.721-0.194
|
||||||
|
c0.165-0.07,0.235-0.227,0.235-0.442v-0.044c0-0.566-0.165-0.988-0.47-1.29c-0.284-0.309-0.751-0.476-1.364-0.476
|
||||||
|
c-0.629,0-1.129,0.141-1.499,0.427c-0.351,0.281-0.602,0.588-0.748,0.891l-1.272-0.442c0.238-0.54,0.516-0.945,0.918-1.247
|
||||||
|
c0.378-0.281,0.772-0.486,1.223-0.616c0.464-0.108,0.886-0.179,1.331-0.179c0.286,0,0.594,0.038,0.967,0.092
|
||||||
|
c0.351,0.065,0.702,0.217,1.05,0.422c0.332,0.194,0.616,0.496,0.851,0.912c0.232,0.405,0.329,0.962,0.329,1.643v5.702h-1.317v-1.166
|
||||||
|
h-0.07c-0.094,0.178-0.229,0.394-0.448,0.604c-0.21,0.216-0.489,0.395-0.842,0.54C337.981,241.995,337.561,242.065,337.044,242.065
|
||||||
|
L337.044,242.065z M337.255,240.866c0.518,0,0.961-0.092,1.339-0.297c0.348-0.216,0.632-0.476,0.823-0.799
|
||||||
|
c0.187-0.335,0.278-0.687,0.278-1.037v-1.215c-0.07,0.069-0.189,0.113-0.373,0.161c-0.189,0.065-0.405,0.119-0.659,0.168
|
||||||
|
c-0.232,0.016-0.472,0.064-0.705,0.086c-0.235,0.027-0.421,0.049-0.562,0.076c-0.354,0.043-0.686,0.113-0.958,0.211
|
||||||
|
c-0.313,0.097-0.548,0.254-0.732,0.447c-0.184,0.217-0.281,0.471-0.281,0.795c0,0.469,0.162,0.82,0.51,1.058
|
||||||
|
C336.294,240.753,336.712,240.866,337.255,240.866L337.255,240.866z M346.971,242.044c-0.799,0-1.507-0.189-2.084-0.578
|
||||||
|
c-0.6-0.384-1.04-0.896-1.367-1.577c-0.302-0.68-0.467-1.452-0.467-2.301c0-0.891,0.165-1.663,0.491-2.349
|
||||||
|
c0.332-0.675,0.775-1.199,1.361-1.566c0.589-0.41,1.267-0.589,2.039-0.589c0.613,0,1.172,0.119,1.666,0.352
|
||||||
|
c0.473,0.205,0.873,0.535,1.194,0.935c0.308,0.399,0.5,0.896,0.591,1.437h-1.337c-0.097-0.405-0.324-0.751-0.678-1.064
|
||||||
|
c-0.348-0.291-0.823-0.464-1.409-0.464c-0.772,0-1.413,0.308-1.879,0.891c-0.475,0.583-0.705,1.388-0.705,2.371
|
||||||
|
c0,0.982,0.23,1.798,0.705,2.392c0.467,0.616,1.107,0.913,1.879,0.913c0.516,0,0.958-0.135,1.333-0.394
|
||||||
|
c0.378-0.287,0.635-0.638,0.753-1.129h1.337c-0.092,0.518-0.284,0.988-0.564,1.388c-0.302,0.421-0.678,0.756-1.169,0.978
|
||||||
|
C348.161,241.925,347.626,242.044,346.971,242.044L346.971,242.044z M352.317,241.854v-8.651h1.336v8.651H352.317z M352.995,231.767
|
||||||
|
c-0.254,0-0.486-0.092-0.678-0.28c-0.165-0.162-0.262-0.379-0.262-0.633c0-0.253,0.097-0.469,0.262-0.637
|
||||||
|
c0.192-0.184,0.424-0.248,0.678-0.248c0.259,0,0.5,0.064,0.659,0.248c0.195,0.168,0.287,0.384,0.287,0.637
|
||||||
|
c0,0.254-0.092,0.471-0.287,0.633C353.494,231.675,353.254,231.767,352.995,231.767L352.995,231.767z M359.613,242.044
|
||||||
|
c-0.799,0-1.482-0.189-2.06-0.557c-0.589-0.389-1.059-0.896-1.388-1.556c-0.329-0.675-0.491-1.457-0.491-2.344
|
||||||
|
c0-0.912,0.162-1.685,0.491-2.37c0.33-0.681,0.799-1.199,1.388-1.577c0.578-0.378,1.261-0.557,2.06-0.557
|
||||||
|
c0.778,0,1.453,0.179,2.042,0.557c0.591,0.378,1.056,0.896,1.38,1.577c0.334,0.686,0.497,1.458,0.497,2.37
|
||||||
|
c0,0.887-0.162,1.669-0.497,2.344c-0.324,0.659-0.789,1.167-1.38,1.556C361.065,241.854,360.391,242.044,359.613,242.044
|
||||||
|
L359.613,242.044z M359.613,240.845c0.591,0,1.08-0.156,1.453-0.438c0.405-0.313,0.681-0.729,0.845-1.226
|
||||||
|
c0.192-0.491,0.284-1.026,0.284-1.594c0-0.588-0.092-1.134-0.284-1.619c-0.165-0.519-0.44-0.913-0.845-1.227
|
||||||
|
c-0.373-0.291-0.861-0.464-1.453-0.464c-0.607,0-1.077,0.173-1.482,0.464c-0.37,0.313-0.651,0.708-0.837,1.227
|
||||||
|
c-0.189,0.485-0.281,1.031-0.281,1.619c0,0.567,0.092,1.103,0.281,1.594c0.186,0.497,0.467,0.912,0.837,1.226
|
||||||
|
C358.536,240.688,359.005,240.845,359.613,240.845L359.613,240.845z M359.005,232.031l1.385-2.635h1.544l-1.758,2.635H359.005z
|
||||||
|
M366.887,236.648v5.206h-1.342v-8.651h1.293v1.361h0.119c0.213-0.454,0.513-0.805,0.937-1.086c0.399-0.265,0.937-0.395,1.596-0.395
|
||||||
|
c0.869,0,1.571,0.275,2.114,0.816c0.535,0.518,0.818,1.365,0.818,2.462v5.492h-1.339v-5.4c0-0.702-0.157-1.215-0.535-1.587
|
||||||
|
c-0.351-0.4-0.827-0.589-1.456-0.589c-0.637,0-1.147,0.21-1.577,0.637C367.101,235.314,366.887,235.903,366.887,236.648
|
||||||
|
L366.887,236.648z M379.322,245.116v-11.913h1.291v1.383h0.162c0.094-0.168,0.208-0.356,0.402-0.589
|
||||||
|
c0.156-0.237,0.418-0.442,0.745-0.638c0.33-0.184,0.775-0.275,1.339-0.275c0.731,0,1.385,0.179,1.922,0.557
|
||||||
|
c0.567,0.356,1.007,0.869,1.313,1.556c0.302,0.659,0.472,1.452,0.472,2.37c0,0.908-0.17,1.713-0.472,2.365
|
||||||
|
c-0.305,0.687-0.746,1.199-1.288,1.556c-0.562,0.367-1.199,0.557-1.917,0.557c-0.57,0-0.991-0.098-1.348-0.281
|
||||||
|
c-0.324-0.188-0.583-0.399-0.767-0.632c-0.165-0.232-0.308-0.442-0.402-0.61h-0.116v4.596H379.322z M380.628,237.54
|
||||||
|
c0,0.966,0.219,1.761,0.643,2.392c0.416,0.616,1.029,0.913,1.85,0.913c0.535,0,1.016-0.135,1.391-0.438
|
||||||
|
c0.37-0.286,0.651-0.686,0.837-1.198c0.189-0.497,0.287-1.054,0.287-1.669c0-0.616-0.097-1.178-0.287-1.669
|
||||||
|
c-0.186-0.491-0.467-0.864-0.815-1.145c-0.396-0.309-0.851-0.448-1.412-0.448c-0.821,0-1.434,0.308-1.85,0.891
|
||||||
|
C380.847,235.785,380.628,236.557,380.628,237.54L380.628,237.54z M391.542,242.065c-0.542,0-1.061-0.119-1.504-0.335
|
||||||
|
c-0.445-0.173-0.799-0.48-1.056-0.886c-0.259-0.394-0.397-0.886-0.397-1.452c0-0.492,0.097-0.887,0.305-1.193
|
||||||
|
c0.186-0.309,0.445-0.567,0.77-0.729c0.33-0.189,0.678-0.303,1.088-0.399c0.4-0.092,0.794-0.168,1.191-0.211
|
||||||
|
c0.54-0.064,0.961-0.119,1.288-0.162c0.33-0.021,0.57-0.098,0.732-0.194c0.143-0.07,0.208-0.227,0.208-0.442v-0.044
|
||||||
|
c0-0.566-0.135-0.988-0.442-1.29c-0.308-0.309-0.751-0.476-1.361-0.476c-0.629,0-1.155,0.141-1.504,0.427
|
||||||
|
c-0.351,0.281-0.61,0.588-0.748,0.891l-1.269-0.442c0.213-0.54,0.516-0.945,0.891-1.247c0.378-0.281,0.802-0.486,1.25-0.616
|
||||||
|
c0.437-0.108,0.888-0.179,1.328-0.179c0.289,0,0.589,0.038,0.964,0.092c0.356,0.065,0.712,0.217,1.061,0.422
|
||||||
|
c0.324,0.194,0.602,0.496,0.84,0.912c0.216,0.405,0.332,0.962,0.332,1.643v5.702h-1.342v-1.166h-0.04
|
||||||
|
c-0.095,0.178-0.265,0.394-0.473,0.604c-0.208,0.216-0.489,0.395-0.824,0.54C392.479,241.995,392.059,242.065,391.542,242.065
|
||||||
|
L391.542,242.065z M391.756,240.866c0.513,0,0.956-0.092,1.334-0.297c0.356-0.216,0.635-0.476,0.824-0.799
|
||||||
|
c0.189-0.335,0.253-0.687,0.253-1.037v-1.215c-0.04,0.069-0.154,0.113-0.345,0.161c-0.189,0.065-0.427,0.119-0.656,0.168
|
||||||
|
c-0.265,0.016-0.494,0.064-0.732,0.086c-0.216,0.027-0.397,0.049-0.562,0.076c-0.33,0.043-0.664,0.113-0.958,0.211
|
||||||
|
c-0.286,0.097-0.551,0.254-0.732,0.447c-0.162,0.217-0.254,0.471-0.254,0.795c0,0.469,0.162,0.82,0.511,1.058
|
||||||
|
C390.792,240.753,391.208,240.866,391.756,240.866L391.756,240.866z M397.945,241.854v-8.651h1.296v1.307h0.086
|
||||||
|
c0.148-0.416,0.424-0.767,0.848-1.053c0.424-0.254,0.891-0.395,1.404-0.395c0.243,0,0.448,0.038,0.637,0.092
|
||||||
|
c0.17,0.049,0.33,0.108,0.47,0.238l-0.448,1.117c-0.089-0.043-0.211-0.092-0.33-0.118c-0.138-0.021-0.278-0.044-0.438-0.044
|
||||||
|
c-0.64,0-1.158,0.189-1.577,0.589c-0.395,0.378-0.608,0.87-0.608,1.458v5.46H397.945z M406.58,242.065
|
||||||
|
c-0.538,0-1.029-0.119-1.475-0.335c-0.451-0.173-0.826-0.48-1.08-0.886c-0.262-0.394-0.402-0.886-0.402-1.452
|
||||||
|
c0-0.492,0.119-0.887,0.305-1.193c0.192-0.309,0.448-0.567,0.772-0.729c0.33-0.189,0.708-0.303,1.102-0.399
|
||||||
|
c0.378-0.092,0.802-0.168,1.202-0.211c0.51-0.064,0.937-0.119,1.267-0.162c0.329-0.021,0.583-0.098,0.726-0.194
|
||||||
|
c0.165-0.07,0.235-0.227,0.235-0.442v-0.044c0-0.566-0.162-0.988-0.47-1.29c-0.281-0.309-0.753-0.476-1.361-0.476
|
||||||
|
c-0.637,0-1.124,0.141-1.501,0.427c-0.348,0.281-0.61,0.588-0.753,0.891l-1.266-0.442c0.24-0.54,0.521-0.945,0.916-1.247
|
||||||
|
c0.373-0.281,0.777-0.486,1.223-0.616c0.47-0.108,0.888-0.179,1.339-0.179c0.278,0,0.613,0.038,0.967,0.092
|
||||||
|
c0.349,0.065,0.694,0.217,1.048,0.422c0.327,0.194,0.61,0.496,0.851,0.912c0.229,0.405,0.321,0.962,0.321,1.643v5.702h-1.313v-1.166
|
||||||
|
h-0.07c-0.092,0.178-0.232,0.394-0.446,0.604c-0.213,0.216-0.494,0.395-0.845,0.54C407.514,241.995,407.099,242.065,406.58,242.065
|
||||||
|
L406.58,242.065z M406.791,240.866c0.519,0,0.964-0.092,1.337-0.297c0.354-0.216,0.634-0.476,0.826-0.799
|
||||||
|
c0.186-0.335,0.278-0.687,0.278-1.037v-1.215c-0.07,0.069-0.189,0.113-0.378,0.161c-0.181,0.065-0.397,0.119-0.651,0.168
|
||||||
|
c-0.232,0.016-0.475,0.064-0.705,0.086c-0.235,0.027-0.424,0.049-0.564,0.076c-0.354,0.043-0.678,0.113-0.964,0.211
|
||||||
|
c-0.302,0.097-0.535,0.254-0.726,0.447c-0.192,0.217-0.281,0.471-0.281,0.795c0,0.469,0.165,0.82,0.513,1.058
|
||||||
|
C405.827,240.753,406.256,240.866,406.791,240.866L406.791,240.866z M418.809,230.309v11.546h-1.345v-11.546H418.809z
|
||||||
|
M423.777,242.065c-0.54,0-1.061-0.119-1.506-0.335c-0.438-0.173-0.792-0.48-1.056-0.886c-0.253-0.394-0.394-0.886-0.394-1.452
|
||||||
|
c0-0.492,0.097-0.887,0.308-1.193c0.184-0.309,0.44-0.567,0.77-0.729c0.329-0.189,0.683-0.303,1.077-0.399
|
||||||
|
c0.399-0.092,0.802-0.168,1.196-0.211c0.545-0.064,0.961-0.119,1.296-0.162c0.324-0.021,0.559-0.098,0.727-0.194
|
||||||
|
c0.146-0.07,0.213-0.227,0.213-0.442v-0.044c0-0.566-0.146-0.988-0.451-1.29c-0.294-0.309-0.748-0.476-1.358-0.476
|
||||||
|
c-0.635,0-1.145,0.141-1.499,0.427c-0.383,0.281-0.613,0.588-0.777,0.891l-1.24-0.442c0.208-0.54,0.513-0.945,0.886-1.247
|
||||||
|
c0.378-0.281,0.802-0.486,1.242-0.616c0.451-0.108,0.896-0.179,1.342-0.179c0.281,0,0.58,0.038,0.958,0.092
|
||||||
|
c0.348,0.065,0.705,0.217,1.058,0.422c0.33,0.194,0.613,0.496,0.845,0.912c0.206,0.405,0.321,0.962,0.321,1.643v5.702h-1.328v-1.166
|
||||||
|
h-0.049c-0.097,0.178-0.262,0.394-0.47,0.604c-0.208,0.216-0.497,0.395-0.821,0.54C424.717,241.995,424.271,242.065,423.777,242.065
|
||||||
|
L423.777,242.065z M423.988,240.866c0.516,0,0.961-0.092,1.339-0.297c0.354-0.216,0.629-0.476,0.821-0.799
|
||||||
|
c0.165-0.335,0.259-0.687,0.259-1.037v-1.215c-0.049,0.069-0.165,0.113-0.356,0.161c-0.192,0.065-0.413,0.119-0.659,0.168
|
||||||
|
c-0.259,0.016-0.486,0.064-0.721,0.086c-0.24,0.027-0.429,0.049-0.564,0.076c-0.33,0.043-0.653,0.113-0.961,0.211
|
||||||
|
c-0.313,0.097-0.537,0.254-0.724,0.447c-0.165,0.217-0.267,0.471-0.267,0.795c0,0.469,0.167,0.82,0.521,1.058
|
||||||
|
C423.002,240.753,423.454,240.866,423.988,240.866L423.988,240.866z M434.641,241.854v-8.651h1.336v8.651H434.641z M435.321,231.767
|
||||||
|
c-0.259,0-0.47-0.092-0.656-0.28c-0.194-0.162-0.286-0.379-0.286-0.633c0-0.253,0.092-0.469,0.286-0.637
|
||||||
|
c0.187-0.184,0.397-0.248,0.656-0.248c0.256,0,0.492,0.064,0.678,0.248c0.192,0.168,0.284,0.384,0.284,0.637
|
||||||
|
c0,0.254-0.092,0.471-0.284,0.633C435.813,231.675,435.577,231.767,435.321,231.767L435.321,231.767z M439.754,236.648v5.206h-1.342
|
||||||
|
v-8.651h1.291v1.361h0.122c0.187-0.454,0.492-0.805,0.916-1.086c0.421-0.265,0.937-0.395,1.593-0.395
|
||||||
|
c0.896,0,1.596,0.275,2.136,0.816c0.535,0.518,0.799,1.365,0.799,2.462v5.492h-1.313v-5.4c0-0.702-0.192-1.215-0.54-1.587
|
||||||
|
c-0.356-0.4-0.851-0.589-1.461-0.589c-0.634,0-1.164,0.21-1.571,0.637C439.965,235.314,439.754,235.903,439.754,236.648
|
||||||
|
L439.754,236.648z M451.228,242.044c-0.826,0-1.506-0.189-2.087-0.578c-0.589-0.384-1.062-0.896-1.364-1.577
|
||||||
|
c-0.305-0.68-0.47-1.452-0.47-2.301c0-0.891,0.165-1.663,0.491-2.349c0.305-0.675,0.786-1.199,1.364-1.566
|
||||||
|
c0.586-0.41,1.264-0.589,2.039-0.589c0.613,0,1.15,0.119,1.642,0.352c0.492,0.205,0.891,0.535,1.199,0.935
|
||||||
|
c0.321,0.399,0.516,0.896,0.588,1.437h-1.32c-0.116-0.405-0.327-0.751-0.678-1.064c-0.348-0.291-0.818-0.464-1.404-0.464
|
||||||
|
c-0.772,0-1.412,0.308-1.874,0.891c-0.476,0.583-0.71,1.388-0.71,2.371c0,0.982,0.213,1.798,0.71,2.392
|
||||||
|
c0.461,0.616,1.072,0.913,1.874,0.913c0.516,0,0.958-0.135,1.329-0.394c0.378-0.287,0.616-0.638,0.753-1.129h1.32
|
||||||
|
c-0.073,0.518-0.267,0.988-0.54,1.388c-0.311,0.421-0.705,0.756-1.177,0.978C452.418,241.925,451.857,242.044,451.228,242.044
|
||||||
|
L451.228,242.044z M457.911,230.309v11.546h-1.336v-11.546H457.911z M465.792,238.317v-5.114h1.339v8.651h-1.339v-1.447h-0.089
|
||||||
|
c-0.192,0.411-0.521,0.794-0.945,1.102c-0.418,0.324-0.985,0.459-1.617,0.459c-0.815,0-1.499-0.253-2.02-0.794
|
||||||
|
c-0.513-0.539-0.794-1.36-0.794-2.462v-5.509h1.342v5.417c0,0.637,0.184,1.128,0.535,1.501c0.356,0.373,0.794,0.567,1.361,0.567
|
||||||
|
c0.327,0,0.656-0.07,1.013-0.26c0.345-0.167,0.632-0.427,0.869-0.777C465.682,239.301,465.792,238.857,465.792,238.317
|
||||||
|
L465.792,238.317z"/>
|
||||||
|
<path fill="#2A2A2B" d="M475.694,235.147l-1.202,0.324c-0.113-0.303-0.3-0.589-0.581-0.843c-0.289-0.259-0.699-0.399-1.291-0.399
|
||||||
|
c-0.519,0-0.961,0.118-1.313,0.378c-0.354,0.232-0.543,0.54-0.543,0.907c0,0.341,0.138,0.589,0.378,0.777
|
||||||
|
c0.24,0.211,0.604,0.356,1.128,0.503l1.285,0.297c1.526,0.378,2.298,1.177,2.298,2.344c0,0.523-0.14,0.945-0.418,1.339
|
||||||
|
c-0.281,0.399-0.686,0.713-1.202,0.913c-0.516,0.237-1.104,0.356-1.76,0.356c-0.891,0-1.615-0.189-2.204-0.578
|
||||||
|
c-0.586-0.384-0.934-0.945-1.099-1.674l1.266-0.329c0.235,0.944,0.916,1.403,2.015,1.403c0.615,0,1.104-0.135,1.479-0.394
|
||||||
|
c0.354-0.26,0.538-0.584,0.538-0.967c0-0.605-0.421-1-1.286-1.21l-1.437-0.335c-0.793-0.184-1.38-0.491-1.733-0.891
|
||||||
|
c-0.378-0.373-0.559-0.896-0.559-1.48c0-0.491,0.138-0.912,0.395-1.29c0.283-0.373,0.656-0.675,1.15-0.892
|
||||||
|
c0.472-0.205,1.012-0.324,1.62-0.324c0.861,0,1.55,0.179,2.014,0.557C475.132,234.019,475.483,234.51,475.694,235.147
|
||||||
|
L475.694,235.147z M477.854,241.854v-8.651h1.336v8.651H477.854z M478.535,231.767c-0.262,0-0.47-0.092-0.659-0.28
|
||||||
|
c-0.192-0.162-0.284-0.379-0.284-0.633c0-0.253,0.092-0.469,0.284-0.637c0.189-0.184,0.397-0.248,0.659-0.248
|
||||||
|
c0.254,0,0.492,0.064,0.681,0.248c0.186,0.168,0.286,0.384,0.286,0.637c0,0.254-0.1,0.471-0.286,0.633
|
||||||
|
C479.026,231.675,478.789,231.767,478.535,231.767L478.535,231.767z M485.147,242.044c-0.796,0-1.474-0.189-2.068-0.557
|
||||||
|
c-0.581-0.389-1.026-0.896-1.35-1.556c-0.335-0.675-0.505-1.457-0.505-2.344c0-0.912,0.17-1.685,0.505-2.37
|
||||||
|
c0.324-0.681,0.77-1.199,1.35-1.577c0.594-0.378,1.272-0.557,2.068-0.557c0.778,0,1.456,0.179,2.044,0.557
|
||||||
|
c0.608,0.378,1.056,0.896,1.38,1.577c0.327,0.686,0.494,1.458,0.494,2.37c0,0.887-0.167,1.669-0.494,2.344
|
||||||
|
c-0.324,0.659-0.772,1.167-1.38,1.556C486.603,241.854,485.925,242.044,485.147,242.044L485.147,242.044z M485.147,240.845
|
||||||
|
c0.589,0,1.083-0.156,1.456-0.438c0.399-0.313,0.678-0.729,0.867-1.226c0.165-0.491,0.262-1.026,0.262-1.594
|
||||||
|
c0-0.588-0.097-1.134-0.262-1.619c-0.189-0.519-0.467-0.913-0.867-1.227c-0.373-0.291-0.867-0.464-1.456-0.464
|
||||||
|
c-0.61,0-1.077,0.173-1.474,0.464c-0.381,0.313-0.662,0.708-0.848,1.227c-0.189,0.485-0.278,1.031-0.278,1.619
|
||||||
|
c0,0.567,0.089,1.103,0.278,1.594c0.187,0.497,0.467,0.912,0.848,1.226C484.07,240.688,484.537,240.845,485.147,240.845
|
||||||
|
L485.147,240.845z M484.537,232.031l1.388-2.635h1.544l-1.755,2.635H484.537z M492.425,236.648v5.206h-1.315v-8.651h1.288v1.361
|
||||||
|
h0.095c0.213-0.454,0.516-0.805,0.937-1.086c0.402-0.265,0.939-0.395,1.596-0.395c0.867,0,1.59,0.275,2.117,0.816
|
||||||
|
c0.535,0.518,0.818,1.365,0.818,2.462v5.492h-1.345v-5.4c0-0.702-0.162-1.215-0.508-1.587c-0.356-0.4-0.848-0.589-1.455-0.589
|
||||||
|
c-0.637,0-1.172,0.21-1.599,0.637C492.63,235.314,492.425,235.903,492.425,236.648L492.425,236.648z"/>
|
||||||
|
<path fill="#163F75" d="M250.517,155.119c3.775,0,3.982-3.133,3.982-6.216v-30.609c0-3.148-0.208-6.318-3.982-6.318
|
||||||
|
c-3.402,0-4.35,2.98-4.35,5.983v7.484c0,3.641-0.205,7.162-0.626,10.58c-0.429,3.424-1.059,6.27-1.971,8.543
|
||||||
|
c-1.499,3.872-3.402,5.768-5.751,5.768c-2.552,0-3.818-3.71-3.818-11.092c0-7.037,0.259-13.35,0.753-18.961
|
||||||
|
c0.235-2.273,0.354-4.077,0.354-5.417c0-1.971-1.085-2.959-3.243-2.959c-1.201,0-2,0.454-2.459,1.313
|
||||||
|
c-1.296,2.44-1.95,10.893-1.95,25.322c0,11.26,3.005,16.579,9.194,16.579c3.259,0,5.983-1.663,8.098-4.995
|
||||||
|
c0.721-1.103,1.142-1.686,1.261-1.686c0.094,0,0.159,0.238,0.159,0.745C246.167,152.192,247.115,155.119,250.517,155.119
|
||||||
|
L250.517,155.119z M287.159,155.119c1.169,0,1.971-0.427,2.443-1.285c1.24-2.484,1.896-10.903,1.896-25.307
|
||||||
|
c0-3.435-0.259-6.275-0.772-8.619c-1.177-5.352-3.964-8.003-8.395-8.003c-3.664,0-6.572,1.928-8.708,5.772
|
||||||
|
c-0.281,0.551-0.521,0.778-0.659,0.778c-0.138,0-0.216-0.205-0.216-0.616c0-3.958-1.426-5.935-4.334-5.935
|
||||||
|
c-1.55,0-2.625,0.523-3.194,1.464c-0.532,0.912-0.796,2.506-0.796,4.779v30.598c0,1.054,0.07,2.063,0.21,3.02
|
||||||
|
c0.335,2.209,1.599,3.289,3.78,3.289c1.855,0,3.122-0.896,3.797-2.663c0.356-0.95,0.537-2.058,0.537-3.348v-7.928
|
||||||
|
c0-8.182,0.875-14.382,2.582-18.681c1.555-3.823,3.478-5.746,5.805-5.746c1.677,0,2.86,1.647,3.394,4.839
|
||||||
|
c0.333,1.923,0.476,4.315,0.476,7.178c-0.021,6.054-0.284,12.064-0.826,18.063c-0.232,2.274-0.354,4.078-0.354,5.4
|
||||||
|
c0,1.988,1.11,2.949,3.292,2.949H287.159z M316.507,128.123c0,2.808-0.21,5.719-0.634,8.748c-0.397,3.003-1.059,5.557-1.874,7.599
|
||||||
|
c-1.526,3.823-3.429,5.724-5.725,5.724c-2.935,0.141-3.85-6.475-3.85-13.512c0-4.784,1.439-19.679,8.284-19.679
|
||||||
|
c1.855,0,3.027,0.47,3.47,1.404c0.237,0.476,0.329,1.01,0.329,1.577V128.123z M324.837,105.268c0-3.094-0.146-6.264-3.964-6.264
|
||||||
|
c-3.362,0-4.366,2.916-4.366,5.983v7.177c0,0.54-0.064,0.848-0.235,0.848c-0.186,0-0.473-0.118-0.842-0.308
|
||||||
|
c-1.056-0.54-2.185-0.799-3.381-0.799c-4.525,0-8.065,2.608-10.606,7.793c-2.392,4.931-3.585,11.373-3.585,19.284
|
||||||
|
c0,8.517,3.121,16.212,9.221,16.072c3.284,0,5.979-1.696,8.139-5.05c0.656-1.031,1.01-1.566,1.123-1.566
|
||||||
|
c0.103,0,0.167,0.206,0.167,0.605c0,3.072,1.004,6.011,4.366,6.011c3.818,0,3.964-3.176,3.964-6.309V105.268z M354.839,155.055
|
||||||
|
c3.851,0.064,3.918-3.197,3.988-6.309v-30.565c-0.07-3.035-0.138-6.324-3.988-6.275c-1.307,0-2.317,0.405-2.935,1.198
|
||||||
|
c-0.205,0.266-0.467,0.405-0.796,0.405c-0.229,0-0.583-0.097-0.932-0.329c-1.434-0.82-2.841-1.274-4.229-1.274
|
||||||
|
c-4.528,0-8.047,2.608-10.601,7.793c-2.39,4.931-3.588,11.373-3.588,19.284c0,8.517,3.119,16.212,9.245,16.072
|
||||||
|
c3.653,0,6.589-2.021,8.768-6.033c0.257-0.469,0.448-0.701,0.567-0.701c0.094,0,0.156,0.254,0.156,0.724
|
||||||
|
C350.494,152.116,351.507,155.055,354.839,155.055L354.839,155.055z M342.175,150.193c-2.911,0.141-3.855-6.475-3.855-13.512
|
||||||
|
c0-4.784,1.437-19.679,8.284-19.679c2.605,0,3.891,0.935,3.891,2.813v9.947c0,1.831-0.2,4.197-0.626,7.107
|
||||||
|
c-0.445,2.938-1.083,5.486-1.971,7.599C346.396,148.293,344.495,150.193,342.175,150.193L342.175,150.193z M379.405,154.979
|
||||||
|
c2.762,0,5.02-0.75,6.802-2.252c1.785-1.507,3.024-3.461,3.64-5.881c0.114-0.324,0.138-0.572,0.138-0.751
|
||||||
|
c0-1.128-0.827-1.804-1.807-1.804c-0.821,0-1.434,0.416-1.809,1.329c-1.191,2.954-2.765,4.434-4.736,4.434
|
||||||
|
c-2.563,0-4.458-1.853-5.754-5.558c-0.843-2.419-1.264-5.146-1.264-8.273c0-7.544,1.013-12.961,3.027-16.266
|
||||||
|
c1.107-1.83,2.328-2.749,3.683-2.749c1.785,0,2.954,1.199,3.567,3.575c0.332,1.404,0.519,3.208,0.519,5.39
|
||||||
|
c0,0.988-0.068,1.923-0.262,2.911c-0.064,0.442-0.094,1.145-0.094,2.014c0,1.453,0.17,2.814,1.906,2.814c1.993,0,3-2.744,3-8.188
|
||||||
|
c0-9.191-3.151-13.793-9.378-13.793c-3.265,0-6.081,1.221-8.408,3.662c-4.01,4.223-6.027,11.098-6.027,20.629
|
||||||
|
c0,3.791,0.47,6.999,1.361,9.607c0.985,2.847,2.533,5.114,4.623,6.832C374.035,154.212,376.465,154.979,379.405,154.979
|
||||||
|
L379.405,154.979z M401.434,109.47c1.566,0,2.724-0.562,3.464-1.69c0.502-0.756,0.761-1.637,0.761-2.7
|
||||||
|
c0-1.14-0.378-2.225-1.158-3.181c-0.748-0.988-1.761-1.485-3-1.485c-2.465,0-4.174,2.111-4.174,5.136
|
||||||
|
C397.327,108.179,398.69,109.47,401.434,109.47L401.434,109.47z M401.263,155.055c2.917,0,4.396-2.021,4.396-6.011v-30.863
|
||||||
|
c0-4.649-1.083-6.275-3.969-6.275c-2.881,0-4.363,2.095-4.363,5.989v30.852c0,1.054,0.067,2.063,0.216,3.02
|
||||||
|
C397.861,153.975,399.084,155.055,401.263,155.055L401.263,155.055z M429.821,149.843c-2.89,0-5.047-1.712-6.475-5.093
|
||||||
|
c-1.245-2.997-1.855-7.053-1.855-12.215c0-10.531,3.024-15.846,9.051-15.846c2.778,0,4.763,1.739,6.032,5.195
|
||||||
|
c0.958,2.668,1.428,6.017,1.428,10.083c0,4.903-0.61,8.965-1.801,12.221C434.792,147.937,432.653,149.843,429.821,149.843
|
||||||
|
L429.821,149.843z M427.542,154.979c5.582,0,9.737-2.203,12.386-6.583c2.301-3.926,3.451-9.288,3.451-16.099
|
||||||
|
c0-5.368-0.821-9.813-2.527-13.252c-2.328-4.736-5.986-7.14-11.009-7.14c-5.773,0-10.088,2.214-12.926,6.643
|
||||||
|
c-2.511,3.845-3.775,9.104-3.775,15.764c0,5.659,1.004,10.255,3.019,13.819C418.728,152.705,422.527,154.979,427.542,154.979
|
||||||
|
L427.542,154.979z M425.924,108.67c1.288,0,3.213-0.799,5.773-2.349c2.549-1.545,3.869-3.116,3.869-4.661
|
||||||
|
c0-1.339-0.659-1.998-1.974-1.998c-1.239,0-3.051,1.129-5.395,3.402c-2.322,2.23-3.47,3.732-3.47,4.574
|
||||||
|
C424.728,108.319,425.122,108.67,425.924,108.67L425.924,108.67z M472.821,155.119c1.19,0,1.968-0.427,2.441-1.285
|
||||||
|
c1.239-2.484,1.898-10.903,1.898-25.307c0-3.435-0.259-6.275-0.756-8.619c-1.188-5.352-3.98-8.003-8.419-8.003
|
||||||
|
c-3.662,0-6.545,1.928-8.703,5.772c-0.278,0.551-0.491,0.778-0.629,0.778c-0.143,0-0.213-0.205-0.213-0.616
|
||||||
|
c0-3.958-1.458-5.935-4.364-5.935c-1.525,0-2.608,0.523-3.188,1.464c-0.545,0.912-0.799,2.506-0.799,4.779v30.598
|
||||||
|
c0,1.054,0.097,2.063,0.232,3.02c0.308,2.209,1.574,3.289,3.756,3.289c1.879,0,3.116-0.896,3.829-2.663
|
||||||
|
c0.343-0.95,0.535-2.058,0.535-3.348v-7.928c0-8.182,0.842-14.382,2.56-18.681c1.566-3.823,3.473-5.746,5.79-5.746
|
||||||
|
c1.717,0,2.886,1.647,3.429,4.839c0.327,1.923,0.464,4.315,0.464,7.178c-0.046,6.054-0.278,12.064-0.84,18.063
|
||||||
|
c-0.235,2.274-0.332,4.078-0.332,5.4c0,1.988,1.085,2.949,3.281,2.949H472.821z"/>
|
||||||
|
<g>
|
||||||
|
<path fill="#163F75" d="M206.898,156.113c3.626,0,4.701-3.09,4.701-6.249v-28.687c0-1.08,0.634-1.625,1.812-1.625l7.788,0.092
|
||||||
|
c1.807,0.092,2.806-0.908,2.806-2.085c0-1.086-0.362-1.814-1.094-2.263c-0.632-0.362-1.537-0.546-2.892-0.546
|
||||||
|
c-2.079,0-4.158,0.184-6.237,0.184c-1.456,0-2.182-0.453-2.182-2.711v-5.427c0-1.998,0.91-2.992,2.725-2.992
|
||||||
|
c0.996,0,2.352,0,3.523,0.098c1.094,0,8.689,0,9.502,0c2.714,0,3.988-1.27,3.988-2.452c0-1.62-1.091-2.533-3.076-2.803
|
||||||
|
c-0.913-0.184-1.636-0.184-2.362-0.184h-9.224h-8.238c-2.986,0-4.79,1.183-5.519,3.629c-0.27,1.172-0.448,2.532-0.448,4.158v43.252
|
||||||
|
c0,1.091,0.086,2.176,0.27,3.17C203.099,154.936,204.46,156.113,206.898,156.113L206.898,156.113z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<defs>
|
||||||
|
<rect id="SVGID_23_" x="-476.587" y="-28.438" width="597.06" height="844.021"/>
|
||||||
|
</defs>
|
||||||
|
<clipPath id="SVGID_2_">
|
||||||
|
<use xlink:href="#SVGID_23_" overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/fundacion/Versión Vertical_Isologotipo FS-26.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
assets/re/Paleta de colores RE-04.jpg
Normal file
|
After Width: | Height: | Size: 798 KiB |
BIN
assets/re/Re-Monocromático.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
assets/re/Re-con fondo color secundario 1.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
assets/re/Re-con fondo color secundario 2.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
assets/re/Re-con fondo color secundario 3.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
assets/re/Re-fondo color primario.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
assets/re/Tipografías-20260604T192900Z-3-001.zip
Normal file
109
components/consent-screen.tsx
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
'use client'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import type { BrandConfig } from '@/lib/types'
|
||||||
|
|
||||||
|
interface ConsentScreenProps {
|
||||||
|
brandConfig: BrandConfig | null
|
||||||
|
onAccept: (consentOperativo: boolean, consentMacroN1: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConsentScreen({ brandConfig, onAccept }: ConsentScreenProps) {
|
||||||
|
const [operativo, setOperativo] = useState(false)
|
||||||
|
const [macroN1, setMacroN1] = useState(false)
|
||||||
|
|
||||||
|
const orgName = brandConfig?.org_name ?? 'tu empresa'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="consent-container" role="main">
|
||||||
|
<h1 className="consent-title">Antes de comenzar</h1>
|
||||||
|
|
||||||
|
<section className="consent-section" aria-labelledby="consent-intro-heading">
|
||||||
|
<h2 id="consent-intro-heading" className="consent-section-title">
|
||||||
|
¿Qué vamos a hacer con tus respuestas?
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Esta encuesta tiene dos propósitos que podés autorizar por separado:
|
||||||
|
</p>
|
||||||
|
<ol className="consent-list">
|
||||||
|
<li>
|
||||||
|
<strong>Diagnóstico interno de {orgName}:</strong> tus respuestas ayudan a la empresa
|
||||||
|
a entender la realidad de las personas que cuidan a familiares con discapacidad o adultos
|
||||||
|
mayores, para diseñar apoyos más adecuados. Solo se trabaja con{' '}
|
||||||
|
<strong>datos agregados</strong> — nunca accede a respuestas individuales.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Estudio país (opcional):</strong> tus respuestas anonimizadas contribuyen a un
|
||||||
|
mapeo nacional sobre la economía del cuidado en Paraguay. Los datos se procesan de
|
||||||
|
forma irreversiblemente desvinculada de cualquier empresa o persona.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Párrafo OBLIGATORIO: anonimato y no-revocación (ADR-003) */}
|
||||||
|
<section className="consent-anon-box" role="note" aria-label="Sobre el anonimato">
|
||||||
|
<p>
|
||||||
|
<strong>Esta encuesta es completamente anónima.</strong> No guardamos ningún dato que
|
||||||
|
te identifique (nombre, número de documento, correo ni ningún otro identificador personal).
|
||||||
|
Por ser anónima, <strong>no es posible revocar ni eliminar tu respuesta una vez enviada</strong>,
|
||||||
|
ya que no habría forma de encontrarla entre las demás.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="consent-checkboxes" aria-labelledby="consent-choices-heading">
|
||||||
|
<h2 id="consent-choices-heading" className="consent-section-title">
|
||||||
|
Tus decisiones
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{/* Checkbox 1: operativo — REQUERIDO */}
|
||||||
|
<label className="consent-checkbox-label" htmlFor="consent-operativo">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="consent-operativo"
|
||||||
|
checked={operativo}
|
||||||
|
onChange={(e) => setOperativo(e.target.checked)}
|
||||||
|
aria-required="true"
|
||||||
|
className="consent-checkbox-input"
|
||||||
|
/>
|
||||||
|
<span className="consent-checkbox-text">
|
||||||
|
<strong>Acepto</strong> que mis respuestas se usen para el diagnóstico interno de{' '}
|
||||||
|
{orgName} sobre cuidado y discapacidad.{' '}
|
||||||
|
<span className="consent-required-badge">Requerido para continuar</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{/* Checkbox 2: macro_n1 — OPCIONAL */}
|
||||||
|
<label className="consent-checkbox-label" htmlFor="consent-macro">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id="consent-macro"
|
||||||
|
checked={macroN1}
|
||||||
|
onChange={(e) => setMacroN1(e.target.checked)}
|
||||||
|
className="consent-checkbox-input"
|
||||||
|
/>
|
||||||
|
<span className="consent-checkbox-text">
|
||||||
|
<strong>También acepto</strong> que mis respuestas anonimizadas contribuyan al estudio
|
||||||
|
país sobre economía del cuidado (sin identificarme en ningún caso).{' '}
|
||||||
|
<span className="consent-optional-badge">Opcional</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="consent-footer">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={!operativo}
|
||||||
|
onClick={() => onAccept(operativo, macroN1)}
|
||||||
|
className={`btn ${operativo ? 'btn-primary' : 'btn-primary btn-disabled'}`}
|
||||||
|
aria-disabled={!operativo}
|
||||||
|
>
|
||||||
|
Comenzar la encuesta
|
||||||
|
</button>
|
||||||
|
{!operativo && (
|
||||||
|
<p className="consent-required-hint" role="status" aria-live="polite">
|
||||||
|
Necesitás marcar el primer checkbox para continuar.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { CheckboxGroup } from './widgets/checkbox-group'
|
|||||||
import { RatingScale } from './widgets/rating-scale'
|
import { RatingScale } from './widgets/rating-scale'
|
||||||
import { TextAreaField } from './widgets/text-area-field'
|
import { TextAreaField } from './widgets/text-area-field'
|
||||||
import { TextShortField } from './widgets/text-short-field'
|
import { TextShortField } from './widgets/text-short-field'
|
||||||
|
import { GeoSelectWidget } from './widgets/geo-select-widget'
|
||||||
|
|
||||||
interface QuestionRendererProps {
|
interface QuestionRendererProps {
|
||||||
question: Question
|
question: Question
|
||||||
@@ -30,6 +31,22 @@ export function QuestionRenderer({
|
|||||||
const { code, type, prompt, required, max_select, options } = question
|
const { code, type, prompt, required, max_select, options } = question
|
||||||
const error = errors[code]
|
const error = errors[code]
|
||||||
|
|
||||||
|
// A1 (Departamento) renders a combined geo widget that also handles A2 (Ciudad)
|
||||||
|
if (code === 'A1') {
|
||||||
|
return (
|
||||||
|
<GeoSelectWidget
|
||||||
|
departmentValue={(answers['A1'] as string) ?? ''}
|
||||||
|
cityValue={(answers['A2'] as string) ?? ''}
|
||||||
|
onDepartmentChange={(v) => onChange('A1', v)}
|
||||||
|
onCityChange={(v) => onChange('A2', v)}
|
||||||
|
departmentError={errors['A1']}
|
||||||
|
cityError={errors['A2']}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// A2 is rendered inside the GeoSelectWidget above — skip here to avoid duplication
|
||||||
|
if (code === 'A2') return null
|
||||||
|
|
||||||
if (type === 'single_choice' && isArrayOptions(options)) {
|
if (type === 'single_choice' && isArrayOptions(options)) {
|
||||||
return (
|
return (
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState, useTransition } from 'react'
|
||||||
import type { FormAnswers, Question, Survey } from '@/lib/types'
|
import type { FormAnswers, Question, Survey } from '@/lib/types'
|
||||||
import { clearDraft, loadDraft, saveDraft } from '@/lib/storage'
|
import { clearDraft, loadDraft, saveDraft } from '@/lib/storage'
|
||||||
import { getHiddenCodes, isQuestionVisible } from '@/lib/conditional'
|
import { getHiddenCodes, isQuestionVisible } from '@/lib/conditional'
|
||||||
|
import { submitSurvey } from '@/app/actions/submit-survey'
|
||||||
|
import { ConsentScreen } from './consent-screen'
|
||||||
import { ProgressBar } from './progress-bar'
|
import { ProgressBar } from './progress-bar'
|
||||||
import { QuestionRenderer } from './question-renderer'
|
import { QuestionRenderer } from './question-renderer'
|
||||||
import { SummaryScreen } from './summary-screen'
|
|
||||||
|
|
||||||
// Section metadata (code prefix → display title)
|
// Section metadata (code prefix → display title)
|
||||||
// Prefixes: 'A' for A1-A7, '1' for 1.1-1.16, '2' for 2.1-2.5, etc.
|
|
||||||
const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
|
const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
|
||||||
{ prefix: 'A', title: 'Datos Generales' },
|
{ prefix: 'A', title: 'Datos Generales' },
|
||||||
{ prefix: '1', title: 'Prevalencia: cuidado y discapacidad', sensitive: true },
|
{ prefix: '1', title: 'Prevalencia: cuidado y discapacidad', sensitive: true },
|
||||||
@@ -20,29 +20,29 @@ const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
|
|||||||
{ prefix: '7', title: 'Para cerrar' },
|
{ prefix: '7', title: 'Para cerrar' },
|
||||||
]
|
]
|
||||||
|
|
||||||
// Extracts the leading alpha or numeric segment from a question code.
|
|
||||||
// 'A1' → 'A', '1.1' → '1', '1.16' → '1', '6.4' → '6', '7.1' → '7'
|
|
||||||
function getSectionPrefix(code: string): string {
|
function getSectionPrefix(code: string): string {
|
||||||
const m = code.match(/^([A-Za-z]+|\d+)/)
|
const m = code.match(/^([A-Za-z]+|\d+)/)
|
||||||
return m ? m[1] : code
|
return m ? m[1] : code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormStage = 'consent' | 'form' | 'success' | 'error'
|
||||||
|
|
||||||
interface SurveyFormProps {
|
interface SurveyFormProps {
|
||||||
survey: Survey
|
survey: Survey
|
||||||
questions: Question[]
|
questions: Question[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
||||||
|
const [stage, setStage] = useState<FormStage>('consent')
|
||||||
|
const [consentOperativo, setConsentOperativo] = useState(false)
|
||||||
|
const [consentMacroN1, setConsentMacroN1] = useState(false)
|
||||||
const [answers, setAnswers] = useState<FormAnswers>({})
|
const [answers, setAnswers] = useState<FormAnswers>({})
|
||||||
const [errors, setErrors] = useState<Record<string, string>>({})
|
const [errors, setErrors] = useState<Record<string, string>>({})
|
||||||
const [submitted, setSubmitted] = useState(false)
|
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||||
const [hydrated, setHydrated] = useState(false)
|
const [isPending, startTransition] = useTransition()
|
||||||
|
|
||||||
// Announce when conditional blocks appear/disappear
|
|
||||||
const [a11yAnnounce, setA11yAnnounce] = useState('')
|
const [a11yAnnounce, setA11yAnnounce] = useState('')
|
||||||
|
const [hydrated, setHydrated] = useState(false)
|
||||||
// Track which trigger codes had "Sí" on prev render to detect toggle
|
const prevAnswers = useRef<FormAnswers>({})
|
||||||
const prevVisibility = useRef<Record<string, boolean>>({})
|
|
||||||
|
|
||||||
// Hydrate from localStorage on mount
|
// Hydrate from localStorage on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -51,43 +51,34 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
setHydrated(true)
|
setHydrated(true)
|
||||||
}, [survey.id])
|
}, [survey.id])
|
||||||
|
|
||||||
// Persist to localStorage on every change (after hydration)
|
// Persist to localStorage after hydration
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!hydrated) return
|
if (!hydrated) return
|
||||||
saveDraft(survey.id, answers)
|
saveDraft(survey.id, answers)
|
||||||
|
prevAnswers.current = answers
|
||||||
}, [answers, hydrated, survey.id])
|
}, [answers, hydrated, survey.id])
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(code: string, value: FormAnswers[string]) => {
|
(code: string, value: FormAnswers[string]) => {
|
||||||
setAnswers((prev) => {
|
setAnswers((prev) => {
|
||||||
const updated = { ...prev, [code]: value }
|
const updated = { ...prev, [code]: value }
|
||||||
|
|
||||||
// Clear any dependent questions that become hidden
|
|
||||||
const toHide = getHiddenCodes(code, value, questions, prev)
|
const toHide = getHiddenCodes(code, value, questions, prev)
|
||||||
for (const hiddenCode of toHide) {
|
for (const hiddenCode of toHide) {
|
||||||
updated[hiddenCode] = undefined as unknown as FormAnswers[string]
|
updated[hiddenCode] = undefined as unknown as FormAnswers[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Announce block visibility change to screen readers
|
|
||||||
if (toHide.length > 0) {
|
if (toHide.length > 0) {
|
||||||
setA11yAnnounce('Se ocultaron preguntas relacionadas y se limpiaron sus respuestas.')
|
setA11yAnnounce('Se ocultaron preguntas relacionadas y se limpiaron sus respuestas.')
|
||||||
} else {
|
} else {
|
||||||
// Check if a conditional block just became visible
|
|
||||||
const appeared = questions.some(
|
const appeared = questions.some(
|
||||||
(q) =>
|
(q) =>
|
||||||
q.conditional_rules?.some((r) => r.if_question === code) &&
|
q.conditional_rules?.some((r) => r.if_question === code) &&
|
||||||
isQuestionVisible(q, updated) &&
|
isQuestionVisible(q, updated) &&
|
||||||
!isQuestionVisible(q, prev)
|
!isQuestionVisible(q, prev)
|
||||||
)
|
)
|
||||||
if (appeared) {
|
if (appeared) setA11yAnnounce('Aparecieron nuevas preguntas según tu respuesta.')
|
||||||
setA11yAnnounce('Aparecieron nuevas preguntas según tu respuesta.')
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return updated
|
return updated
|
||||||
})
|
})
|
||||||
|
|
||||||
// Clear validation error for this field
|
|
||||||
setErrors((prev) => {
|
setErrors((prev) => {
|
||||||
if (!prev[code]) return prev
|
if (!prev[code]) return prev
|
||||||
const { [code]: _, ...rest } = prev
|
const { [code]: _, ...rest } = prev
|
||||||
@@ -103,12 +94,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
if (!q.required) continue
|
if (!q.required) continue
|
||||||
if (!isQuestionVisible(q, answers)) continue
|
if (!isQuestionVisible(q, answers)) continue
|
||||||
const val = answers[q.code]
|
const val = answers[q.code]
|
||||||
if (
|
if (val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0)) {
|
||||||
val === null ||
|
|
||||||
val === undefined ||
|
|
||||||
val === '' ||
|
|
||||||
(Array.isArray(val) && val.length === 0)
|
|
||||||
) {
|
|
||||||
newErrors[q.code] = 'Este campo es obligatorio.'
|
newErrors[q.code] = 'Este campo es obligatorio.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,82 +104,129 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
|
|
||||||
function handleSubmit(e: React.FormEvent) {
|
function handleSubmit(e: React.FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
if (isPending) return
|
||||||
if (!validate()) {
|
if (!validate()) {
|
||||||
// Move focus to first error
|
|
||||||
const firstErrorCode = Object.keys(errors)[0]
|
const firstErrorCode = Object.keys(errors)[0]
|
||||||
if (firstErrorCode) {
|
if (firstErrorCode) document.getElementById(firstErrorCode)?.focus()
|
||||||
document.getElementById(firstErrorCode)?.focus()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 2A: no write to DB — just show summary
|
|
||||||
|
const questionMap = Object.fromEntries(questions.map((q) => [q.code, q.id]))
|
||||||
|
|
||||||
|
startTransition(async () => {
|
||||||
|
const result = await submitSurvey({
|
||||||
|
surveyId: survey.id,
|
||||||
|
answers: answers as Record<string, unknown>,
|
||||||
|
questionMap,
|
||||||
|
consentOperativo,
|
||||||
|
consentMacroN1,
|
||||||
|
})
|
||||||
|
if (result.success) {
|
||||||
clearDraft(survey.id)
|
clearDraft(survey.id)
|
||||||
setSubmitted(true)
|
setStage('success')
|
||||||
|
} else {
|
||||||
|
setSubmitError(result.error)
|
||||||
|
setStage('error')
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleStartOver() {
|
// ── Stage: consent ──────────────────────────────────────────
|
||||||
setAnswers({})
|
if (stage === 'consent') {
|
||||||
setSubmitted(false)
|
return (
|
||||||
setErrors({})
|
<ConsentScreen
|
||||||
|
brandConfig={survey.brand_config}
|
||||||
|
onAccept={(op, macro) => {
|
||||||
|
setConsentOperativo(op)
|
||||||
|
setConsentMacroN1(macro)
|
||||||
|
setStage('form')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visible questions driven by conditional_rules
|
// ── Stage: success ──────────────────────────────────────────
|
||||||
|
if (stage === 'success') {
|
||||||
|
return (
|
||||||
|
<div className="survey-wrapper">
|
||||||
|
<div className="thank-you-container" role="main">
|
||||||
|
<h1 className="thank-you-title">¡Gracias por participar!</h1>
|
||||||
|
<p className="thank-you-body">
|
||||||
|
Tu respuesta fue registrada correctamente. Recordá que la encuesta es anónima: no hay
|
||||||
|
forma de vincular tus respuestas con tu identidad.
|
||||||
|
</p>
|
||||||
|
<p className="thank-you-body">
|
||||||
|
Los resultados agregados ayudarán a {survey.brand_config?.org_name ?? 'tu empresa'} a
|
||||||
|
diseñar mejores apoyos para las personas cuidadoras.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Stage: error ────────────────────────────────────────────
|
||||||
|
if (stage === 'error') {
|
||||||
|
return (
|
||||||
|
<div className="survey-wrapper">
|
||||||
|
<div className="error-container" role="main">
|
||||||
|
<h1 className="error-title">No se pudo enviar la encuesta</h1>
|
||||||
|
<p>Hubo un error al guardar tus respuestas ({submitError}). Podés intentarlo de nuevo.</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={() => { setSubmitError(null); setStage('form') }}
|
||||||
|
>
|
||||||
|
Volver e intentar de nuevo
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Stage: form ─────────────────────────────────────────────
|
||||||
const visibleQuestions = questions.filter((q) => isQuestionVisible(q, answers))
|
const visibleQuestions = questions.filter((q) => isQuestionVisible(q, answers))
|
||||||
const answeredCount = visibleQuestions.filter((q) => {
|
const answeredCount = visibleQuestions.filter((q) => {
|
||||||
const v = answers[q.code]
|
const v = answers[q.code]
|
||||||
return v !== null && v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)
|
return v !== null && v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0)
|
||||||
}).length
|
}).length
|
||||||
|
|
||||||
if (submitted) {
|
|
||||||
return (
|
|
||||||
<SummaryScreen
|
|
||||||
surveyTitle={survey.title}
|
|
||||||
questions={questions}
|
|
||||||
answers={answers}
|
|
||||||
onStartOver={handleStartOver}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group visible questions by section prefix, in order
|
|
||||||
type Section = { prefix: string; title: string; sensitive?: boolean; questions: Question[] }
|
type Section = { prefix: string; title: string; sensitive?: boolean; questions: Question[] }
|
||||||
const sectionMap = new Map<string, Section>()
|
const sectionMap = new Map<string, Section>()
|
||||||
for (const q of visibleQuestions) {
|
for (const q of visibleQuestions) {
|
||||||
const prefix = getSectionPrefix(q.code)
|
const prefix = getSectionPrefix(q.code)
|
||||||
if (!sectionMap.has(prefix)) {
|
if (!sectionMap.has(prefix)) {
|
||||||
const meta = SECTIONS.find((s) => s.prefix === prefix)
|
const meta = SECTIONS.find((s) => s.prefix === prefix)
|
||||||
sectionMap.set(prefix, {
|
sectionMap.set(prefix, { prefix, title: meta?.title ?? prefix, sensitive: meta?.sensitive, questions: [] })
|
||||||
prefix,
|
|
||||||
title: meta?.title ?? prefix,
|
|
||||||
sensitive: meta?.sensitive,
|
|
||||||
questions: [],
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
sectionMap.get(prefix)!.questions.push(q)
|
sectionMap.get(prefix)!.questions.push(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bc = survey.brand_config
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="survey-wrapper">
|
<div className="survey-wrapper">
|
||||||
{/* Skip link for keyboard users */}
|
<a href="#survey-form" className="skip-link">Ir al formulario</a>
|
||||||
<a href="#survey-form" className="skip-link">
|
|
||||||
Ir al formulario
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/* Screen-reader live region for conditional announcements */}
|
<div aria-live="polite" aria-atomic="true" className="sr-only" role="status">
|
||||||
<div
|
|
||||||
aria-live="polite"
|
|
||||||
aria-atomic="true"
|
|
||||||
className="sr-only"
|
|
||||||
role="status"
|
|
||||||
>
|
|
||||||
{a11yAnnounce}
|
{a11yAnnounce}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Header contextual con org/branch si está configurado */}
|
||||||
|
{bc?.org_name && (
|
||||||
|
<div className="brand-header" role="note" aria-label="Información de la empresa">
|
||||||
|
<p className="brand-text">
|
||||||
|
Estás respondiendo esto porque pertenecés a <strong>{bc.org_name}</strong>
|
||||||
|
{bc.branch_name && (
|
||||||
|
<> y participás en las oficinas de <strong>{bc.branch_name}</strong>
|
||||||
|
{bc.branch_city && <> en <strong>{bc.branch_city}</strong></>}.</>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<header className="survey-header">
|
<header className="survey-header">
|
||||||
<h1 className="survey-title">{survey.title}</h1>
|
<h1 className="survey-title">{survey.title}</h1>
|
||||||
<p className="survey-anon-note">
|
<p className="survey-anon-note">Esta encuesta es anónima. Tus respuestas no te identifican.</p>
|
||||||
Esta encuesta es anónima. Tus respuestas no te identifican.
|
|
||||||
</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="survey-progress-sticky" aria-label="Barra de progreso">
|
<div className="survey-progress-sticky" aria-label="Barra de progreso">
|
||||||
@@ -201,11 +234,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main id="survey-form">
|
<main id="survey-form">
|
||||||
<form
|
<form onSubmit={handleSubmit} noValidate aria-label={`Encuesta: ${survey.title}`}>
|
||||||
onSubmit={handleSubmit}
|
|
||||||
noValidate
|
|
||||||
aria-label={`Encuesta: ${survey.title}`}
|
|
||||||
>
|
|
||||||
{Array.from(sectionMap.values()).map((section) => (
|
{Array.from(sectionMap.values()).map((section) => (
|
||||||
<section
|
<section
|
||||||
key={section.prefix}
|
key={section.prefix}
|
||||||
@@ -213,9 +242,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
aria-labelledby={`section-${section.prefix}`}
|
aria-labelledby={`section-${section.prefix}`}
|
||||||
>
|
>
|
||||||
<div className="section-header">
|
<div className="section-header">
|
||||||
<h2 id={`section-${section.prefix}`} className="section-title">
|
<h2 id={`section-${section.prefix}`} className="section-title">{section.title}</h2>
|
||||||
{section.title}
|
|
||||||
</h2>
|
|
||||||
{section.sensitive && (
|
{section.sensitive && (
|
||||||
<p className="section-sensitive-note" role="note">
|
<p className="section-sensitive-note" role="note">
|
||||||
Esta sección contiene preguntas sensibles sobre salud o discapacidad.
|
Esta sección contiene preguntas sensibles sobre salud o discapacidad.
|
||||||
@@ -223,13 +250,8 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{section.questions.map((q) => (
|
{section.questions.map((q) => (
|
||||||
<div
|
<div key={q.id} className="question-wrapper" data-code={q.code}>
|
||||||
key={q.id}
|
|
||||||
className="question-wrapper"
|
|
||||||
data-code={q.code}
|
|
||||||
>
|
|
||||||
<QuestionRenderer
|
<QuestionRenderer
|
||||||
question={q}
|
question={q}
|
||||||
answers={answers}
|
answers={answers}
|
||||||
@@ -242,8 +264,13 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
<div className="form-footer">
|
<div className="form-footer">
|
||||||
<button type="submit" className="btn btn-primary">
|
<button
|
||||||
Ver resumen de respuestas
|
type="submit"
|
||||||
|
className="btn btn-primary"
|
||||||
|
disabled={isPending}
|
||||||
|
aria-disabled={isPending}
|
||||||
|
>
|
||||||
|
{isPending ? 'Enviando…' : 'Enviar encuesta'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
90
components/widgets/geo-select-widget.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
'use client'
|
||||||
|
import { DEPARTMENTS, getCities } from '@/lib/paraguay-geo'
|
||||||
|
|
||||||
|
interface GeoSelectWidgetProps {
|
||||||
|
departmentValue: string
|
||||||
|
cityValue: string
|
||||||
|
onDepartmentChange: (value: string) => void
|
||||||
|
onCityChange: (value: string) => void
|
||||||
|
departmentError?: string
|
||||||
|
cityError?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GeoSelectWidget({
|
||||||
|
departmentValue,
|
||||||
|
cityValue,
|
||||||
|
onDepartmentChange,
|
||||||
|
onCityChange,
|
||||||
|
departmentError,
|
||||||
|
cityError,
|
||||||
|
}: GeoSelectWidgetProps) {
|
||||||
|
const cities = departmentValue ? getCities(departmentValue) : []
|
||||||
|
const cityDisabled = !departmentValue
|
||||||
|
|
||||||
|
function handleDepartmentChange(val: string) {
|
||||||
|
onDepartmentChange(val)
|
||||||
|
onCityChange('') // limpiar ciudad al cambiar departamento
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="geo-select-wrapper">
|
||||||
|
{/* Departamento */}
|
||||||
|
<div className="geo-select-group">
|
||||||
|
<label className="question-legend" htmlFor="A1">
|
||||||
|
Departamento
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="A1"
|
||||||
|
name="A1"
|
||||||
|
value={departmentValue}
|
||||||
|
onChange={(e) => handleDepartmentChange(e.target.value)}
|
||||||
|
aria-invalid={!!departmentError}
|
||||||
|
aria-describedby={departmentError ? 'A1-error' : undefined}
|
||||||
|
className="geo-select"
|
||||||
|
>
|
||||||
|
<option value="">Seleccioná un departamento…</option>
|
||||||
|
{DEPARTMENTS.map((dept) => (
|
||||||
|
<option key={dept} value={dept}>{dept}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{departmentError && (
|
||||||
|
<p role="alert" className="field-error" id="A1-error">{departmentError}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Ciudad */}
|
||||||
|
<div className="geo-select-group">
|
||||||
|
<label
|
||||||
|
className={`question-legend${cityDisabled ? ' geo-label-disabled' : ''}`}
|
||||||
|
htmlFor="A2"
|
||||||
|
>
|
||||||
|
Ciudad
|
||||||
|
{cityDisabled && (
|
||||||
|
<span className="geo-disabled-hint"> (seleccioná un departamento primero)</span>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="A2"
|
||||||
|
name="A2"
|
||||||
|
value={cityValue}
|
||||||
|
onChange={(e) => onCityChange(e.target.value)}
|
||||||
|
disabled={cityDisabled}
|
||||||
|
aria-disabled={cityDisabled}
|
||||||
|
aria-invalid={!!cityError}
|
||||||
|
aria-describedby={cityError ? 'A2-error' : undefined}
|
||||||
|
className={`geo-select${cityDisabled ? ' geo-select-disabled' : ''}`}
|
||||||
|
>
|
||||||
|
<option value="">
|
||||||
|
{cityDisabled ? 'Primero seleccioná el departamento' : 'Seleccioná una ciudad…'}
|
||||||
|
</option>
|
||||||
|
{cities.map((city) => (
|
||||||
|
<option key={city} value={city}>{city}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{cityError && (
|
||||||
|
<p role="alert" className="field-error" id="A2-error">{cityError}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
84
lib/paraguay-geo.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// Datos geográficos de Paraguay — departamentos y sus ciudades/municipios
|
||||||
|
// Fuente: INE Paraguay / Wikipedia. Actualizaciones: agregar al objeto GEO_DATA sin cambio de esquema.
|
||||||
|
|
||||||
|
export const GEO_DATA: Record<string, string[]> = {
|
||||||
|
'Asunción (Capital)': ['Asunción'],
|
||||||
|
'Alto Paraguay': ['Fuerte Olimpo', 'Bahía Negra', 'Carmelo Peralta', 'La Victoria'],
|
||||||
|
'Alto Paraná': [
|
||||||
|
'Ciudad del Este', 'Hernandarias', 'Minga Guazú', 'Presidente Franco',
|
||||||
|
'Minga Porã', 'Naranjal', 'Ñacunday', 'San Alberto', 'Santa Rita', 'Tavapy',
|
||||||
|
'Yguazú', "Juan E. O'Leary", 'San Cristóbal', 'Santa Fe del Paraná',
|
||||||
|
'Dr. Juan León Mallorquín', 'Itakyry', 'Domingo Martínez de Irala',
|
||||||
|
],
|
||||||
|
'Amambay': ['Pedro Juan Caballero', 'Bella Vista Norte', 'Capitán Bado', 'Zanja Pytã'],
|
||||||
|
'Boquerón': ['Filadelfia', 'Loma Plata', 'Mariscal Estigarribia', 'Neuland'],
|
||||||
|
'Caaguazú': [
|
||||||
|
'Coronel Oviedo', 'Caaguazú', 'Carayaó', 'Dr. Juan Manuel Frutos', 'Mbutuy',
|
||||||
|
'Nueva Londres', 'Raúl Arsenio Oviedo', 'Repatriación', 'San Joaquín',
|
||||||
|
'San José de los Arroyos', 'Simón Bolívar', 'Vaquería', 'Yhú',
|
||||||
|
'José Domingo Ocampos', '3 de Febrero', 'Mcal. Francisco Solano López', 'Los Cedrales',
|
||||||
|
],
|
||||||
|
'Caazapá': [
|
||||||
|
'Caazapá', 'Abai', 'Buena Vista', 'General Higinio Morínigo', 'Huber Duré',
|
||||||
|
'Maciel', 'San Juan Nepomuceno', 'Tavaí', 'Yegros', 'Yuty',
|
||||||
|
],
|
||||||
|
'Canindeyú': [
|
||||||
|
'Salto del Guairá', 'Corpus Christi', 'Curuguaty', 'General Francisco Caballero Álvarez',
|
||||||
|
'Itanará', 'Katueté', 'La Paloma', 'Nueva Esperanza', 'Yasy Kañy', 'Ypejhú',
|
||||||
|
],
|
||||||
|
'Central': [
|
||||||
|
'Areguá', 'Capiatá', 'Fernando de la Mora', 'Guarambaré', 'Itá', 'Itauguá',
|
||||||
|
'Juan Augusto Saldívar', 'Lambaré', 'Limpio', 'Luque', 'Mariano Roque Alonso',
|
||||||
|
'Nueva Italia', 'Ñemby', 'San Antonio', 'San Lorenzo', 'Villa Elisa', 'Villeta', 'Ypané', 'Ypacaraí',
|
||||||
|
],
|
||||||
|
'Concepción': [
|
||||||
|
'Concepción', 'Belén', 'Horqueta', 'Loreto', 'San Lázaro', 'San Carlos del Apa',
|
||||||
|
"Yby Yaú", "Azote'y", 'Sgto. José Félix López',
|
||||||
|
],
|
||||||
|
'Cordillera': [
|
||||||
|
'Caacupé', 'Altos', 'Arroyos y Esteros', 'Caraguatay', 'Emboscada', 'Eusebio Ayala',
|
||||||
|
'Isla Pucú', 'Itacurubí de la Cordillera', 'Juan de Mena', 'Loma Grande',
|
||||||
|
'Mbocayaty del Yhaguy', 'Nueva Colombia', 'Pirayú', 'Primero de Marzo', 'Tobatí', 'Valenzuela',
|
||||||
|
],
|
||||||
|
'Guairá': [
|
||||||
|
'Villarrica', 'Borja', 'Capitán Mauricio José Troche', 'Coronel Martínez',
|
||||||
|
'Félix Pérez Cardozo', 'General Eugenio A. Garay', 'Independencia', 'Itapé',
|
||||||
|
'Iturbe', 'José Fassardi', 'Mbocayaty', 'Natalicio Talavera', 'Ñumí', 'San Salvador', 'Yataity',
|
||||||
|
],
|
||||||
|
'Itapúa': [
|
||||||
|
'Encarnación', 'Alto Verá', 'Bella Vista', 'Cambyretá', 'Capitán Meza', 'Capitán Miranda',
|
||||||
|
'Carlos A. López', 'Carmen del Paraná', 'Coronel Bogado', 'Cosme', 'Edelira', 'Fram',
|
||||||
|
'General Artigas', 'Hohenau', 'Itapúa Poty', 'Jesús', 'La Paz', 'Leandro Oviedo',
|
||||||
|
'Mayor Otaño', 'Natalio', 'Nueva Alborada', 'Obligado', 'Pirapó', 'San Cosme y Damián',
|
||||||
|
'San Juan del Paraná', 'San Pedro del Paraná', 'San Rafael del Paraná',
|
||||||
|
'Trinidad', 'Tomás Romero Pereira',
|
||||||
|
],
|
||||||
|
'Misiones': [
|
||||||
|
'San Juan Bautista', 'Ayolas', 'San Ignacio', 'San Miguel', 'San Patricio',
|
||||||
|
'Santa María', 'Santa Rosa', 'Santiago', 'Villa Florida', 'Yabebyry',
|
||||||
|
],
|
||||||
|
'Ñeembucú': [
|
||||||
|
'Pilar', 'Alberdi', 'Cerrito', 'Desmochados', 'General José Eduvigis Díaz', 'Guazú Cuá',
|
||||||
|
'Humaitá', 'Isla Umbú', 'Laureles', 'Mayor José de J. Martínez', 'Paso de Patria',
|
||||||
|
'San Juan Bautista del Ñeembucú', 'Tacuaras', 'Villa Franca', 'Villa Oliva', 'Villalba',
|
||||||
|
],
|
||||||
|
'Paraguarí': [
|
||||||
|
'Paraguarí', 'Acahay', 'Carapeguá', 'Escobar', 'General Bernardino Caballero',
|
||||||
|
'La Colmena', 'Mbuyapey', 'Quiindy', 'Quyquyhó', 'San Roque González de Santa Cruz',
|
||||||
|
'Sapucaí', 'Tebicuarymí', 'Ybycuí', 'Ybytymí', 'Yaguarón',
|
||||||
|
],
|
||||||
|
'Presidente Hayes': [
|
||||||
|
'Villa Hayes', 'Benjamín Aceval', 'José Falcón', 'Nanawa', 'Nueva Asunción',
|
||||||
|
'Pozo Colorado', 'Puerto Pinasco', 'Teniente Primero Manuel Irala Fernández', 'Villa del Río',
|
||||||
|
],
|
||||||
|
'San Pedro': [
|
||||||
|
'San Pedro del Ycuamandiyú', 'Antequera', 'Choré', 'General Elizardo Aquino',
|
||||||
|
'Guayaibí', 'Itacurubí del Rosario', 'Lima', 'Nueva Germania', 'Río Verde',
|
||||||
|
'San Estanislao (Santaní)', 'Tacuatí', 'Unión', 'Villa del Rosario', 'Yataity del Norte',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEPARTMENTS = Object.keys(GEO_DATA)
|
||||||
|
|
||||||
|
export const getCities = (department: string): string[] =>
|
||||||
|
GEO_DATA[department] ?? []
|
||||||
@@ -39,12 +39,21 @@ export interface Question {
|
|||||||
conditional_rules: ConditionalRule[] | null
|
conditional_rules: ConditionalRule[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface BrandConfig {
|
||||||
|
org_name?: string
|
||||||
|
branch_name?: string
|
||||||
|
branch_city?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface Survey {
|
export interface Survey {
|
||||||
id: string
|
id: string
|
||||||
|
org_id: string
|
||||||
title: string
|
title: string
|
||||||
status: string
|
status: string
|
||||||
is_anonymous: boolean
|
is_anonymous: boolean
|
||||||
k_threshold: number
|
k_threshold: number
|
||||||
|
consent_version_id: string
|
||||||
|
brand_config: BrandConfig | null
|
||||||
questions: Question[]
|
questions: Question[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
258
sprints/sprint-2/ETAPA_2B_PROMPT.md
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
# ETAPA 2B — Consentimiento + persistencia real + dropdowns geográficos
|
||||||
|
|
||||||
|
> Leé: `CLAUDE.md`, `DATA_MODEL.md`, `SEED_SPEC.md`, `docs/adr/ADR-001`, `docs/adr/ADR-003`,
|
||||||
|
> `sprints/sprint-2/BRIEF.md` y este prompt. La app Next.js ya existe (Etapa 2A).
|
||||||
|
|
||||||
|
## 1. Objetivo
|
||||||
|
Cuatro cosas en una etapa:
|
||||||
|
1. **Geo dropdowns:** A1=Departamento, A2=Ciudad (dependiente de A1), A3=Barrio (texto, opcional).
|
||||||
|
2. **Header contextual:** mostrar organización y sucursal pre-configurados en la encuesta.
|
||||||
|
3. **URL por parámetro:** `?s=UUID` para cargar una encuesta específica.
|
||||||
|
4. **Persistencia real (2B):** pantalla de consentimiento + Server Action que escribe
|
||||||
|
`consent_record → response → answers` en Supabase Cloud.
|
||||||
|
|
||||||
|
## 2. Contexto previo
|
||||||
|
La app renderiza el formulario desde Supabase (anon key), tiene lógica condicional data-driven,
|
||||||
|
widget `text_short`, resiliencia lite. El esquema Sprint 1 tiene RLS, k-anonimato, consent inmutable.
|
||||||
|
`responses.consent_record_id` es `NOT NULL` → la escritura requiere consentimiento primero.
|
||||||
|
|
||||||
|
## 3. Decisiones ya tomadas
|
||||||
|
- **Geo:** A1=Departamento y A2=Ciudad son `single_choice` en el DB, renderizados con un widget
|
||||||
|
especial `GeoSelectWidget` (dos dropdowns enlazados). A3=Barrio es `text_short`, opcional.
|
||||||
|
Los datos geográficos viven en una constante TypeScript en el app (ver sección 5).
|
||||||
|
- **Header:** `survey.brand_config` tiene `{org_name, branch_name, branch_city}`. El formulario
|
||||||
|
lo muestra arriba: *"Estás respondiendo esto porque pertenecés a [org_name] y participás en las
|
||||||
|
oficinas de [branch_name] en [branch_city]."* — solo-lectura, no editable por el respondente.
|
||||||
|
- **URL:** `?s=<survey_id>` — la página lee `searchParams.s`. Si no hay parámetro, carga la primera
|
||||||
|
encuesta `live` (backwards compat para desarrollo).
|
||||||
|
- **Consentimiento:** pantalla ANTES del formulario. Checkbox 1 (requerido): acepta uso operativo.
|
||||||
|
Checkbox 2 (opcional): acepta macro anónimo. Sin checkbox 1, no puede avanzar. El texto debe ser
|
||||||
|
honesto sobre el anonimato y la NO revocación (ADR-003 — la encuesta es anónima; no hay forma de
|
||||||
|
revocar después). Los valores de ambos checkboxes se almacenan en `consent_record.granted_scopes`.
|
||||||
|
- **ip_hash:** se computa SERVER-SIDE en el Server Action con SHA-256 + `process.env.IP_HASH_SALT`
|
||||||
|
(variable server-only, **nunca** `NEXT_PUBLIC_`). Usar `x-forwarded-for` como IP (Traefik/Dokploy).
|
||||||
|
- **Orden de inserts:** consentimiento → response → answers, dentro del Server Action.
|
||||||
|
Si algo falla, el usuario ve un error y puede reintentar.
|
||||||
|
- **`service_role` NUNCA en el cliente.** Los inserts usan el cliente Supabase inicializado con la
|
||||||
|
`anon` key server-side (en el Server Action) — las RLS policies de INSERT lo permiten.
|
||||||
|
|
||||||
|
## 4. Tareas
|
||||||
|
|
||||||
|
### 4A — Seed: actualizar questions y brand_config
|
||||||
|
1. En `supabase/seed.sql`, actualizar:
|
||||||
|
- **A1** (Departamento): `type='single_choice'`, opciones = los 18 valores del listado geo (sección 5).
|
||||||
|
- **A2** (Ciudad): `type='single_choice'`, opciones = TODAS las ciudades del listado geo
|
||||||
|
concatenadas con el nombre de su departamento como prefijo para que la DB las almacene
|
||||||
|
correctamente (e.g. `{label:"Asunción", value:"Asunción"}`). El filtrado por departamento
|
||||||
|
es client-side en el widget.
|
||||||
|
- **A3** (Barrio): `type='text_short'`, prompt="¿En qué barrio vivís? (opcional)", required=false.
|
||||||
|
- **A4** (Área): agregar a las opciones existentes: `"Directorio"` y `"Gerencia"`.
|
||||||
|
- **1.3** (Elementos de apoyo): agregar opción `"Tecnología asistiva"`.
|
||||||
|
- **survey.brand_config**: actualizar el registro semilla con
|
||||||
|
`{"org_name": "Empresa Demo", "branch_name": "Oficina Central", "branch_city": "Asunción"}`.
|
||||||
|
(El director actualizará esto con los datos reales de la primera empresa directamente en
|
||||||
|
Supabase Studio antes de enviar el link.)
|
||||||
|
2. Aplicar a Cloud: `supabase db push --include-seed` o actualizar las questions directamente
|
||||||
|
via script SQL si el seed ya no es idempotente (usar ON CONFLICT UPDATE para questions).
|
||||||
|
|
||||||
|
### 4B — App: GeoSelectWidget + header + URL
|
||||||
|
3. Crear `components/widgets/geo-select-widget.tsx`:
|
||||||
|
- Primer dropdown: Departamento (opciones de A1).
|
||||||
|
- Segundo dropdown: Ciudad — opciones filtradas del `GEO_DATA` const según el departamento
|
||||||
|
seleccionado. Deshabilitado hasta que se seleccione departamento.
|
||||||
|
- Cuando cambia el departamento, limpiar la ciudad seleccionada.
|
||||||
|
- Ambos dropdowns son accesibles (label, aria, teclado).
|
||||||
|
4. En `question-renderer.tsx`: detectar `code === 'A1'` → renderizar `GeoSelectWidget` (que
|
||||||
|
maneja A1 y A2 juntos). Detectar `code === 'A2'` → skip (ya lo maneja el widget de A1).
|
||||||
|
5. En `app/page.tsx`:
|
||||||
|
- Leer `searchParams.s` como `surveyId`. Si existe, cargar esa encuesta por ID; si no, cargar
|
||||||
|
la primera `live`.
|
||||||
|
- Leer `survey.brand_config` y pasarlo al formulario.
|
||||||
|
6. Crear el **header contextual** (component o inline en `survey-form.tsx`): si `brand_config`
|
||||||
|
tiene `org_name`, mostrar el banner:
|
||||||
|
*"Estás respondiendo esto porque pertenecés a [org_name] y participás en las oficinas de
|
||||||
|
[branch_name] en [branch_city]."* — estilo discreto, no editable.
|
||||||
|
|
||||||
|
### 4C — Consentimiento (pantalla previa al formulario)
|
||||||
|
7. Crear `components/consent-screen.tsx`:
|
||||||
|
- Sección de explicación del tratamiento (qué se recolecta, para qué, que es anónimo).
|
||||||
|
- Párrafo OBLIGATORIO sobre anonimato: *"Esta encuesta es completamente anónima. No guardamos
|
||||||
|
ningún dato que te identifique. Por ser anónima, no es posible revocar ni eliminar tu
|
||||||
|
respuesta una vez enviada."*
|
||||||
|
- Checkbox 1 (required): *"Acepto que mis respuestas se usen para el diagnóstico interno de
|
||||||
|
[org_name] sobre cuidado y discapacidad."*
|
||||||
|
- Checkbox 2 (optional): *"También acepto que mis respuestas anonimizadas contribuyan al
|
||||||
|
estudio país sobre economía del cuidado (sin identificarme en ningún caso)."*
|
||||||
|
- Botón "Comenzar la encuesta" — deshabilitado hasta que checkbox 1 esté marcado.
|
||||||
|
- Al hacer clic en "Comenzar", guarda los valores de los checkboxes en el estado del formulario
|
||||||
|
y muestra el formulario (NO escribe en la base todavía — el insert va al enviar).
|
||||||
|
|
||||||
|
### 4D — Server Action: persistencia real
|
||||||
|
8. Crear `app/actions/submit-survey.ts` (Server Action):
|
||||||
|
```typescript
|
||||||
|
'use server'
|
||||||
|
import { headers } from 'next/headers'
|
||||||
|
import { createHash } from 'crypto'
|
||||||
|
import { createClient } from '@supabase/supabase-js'
|
||||||
|
|
||||||
|
export async function submitSurvey(payload: {
|
||||||
|
surveyId: string
|
||||||
|
answers: Record<string, unknown> // código → valor
|
||||||
|
questionMap: Record<string, string> // código → question_id (UUID)
|
||||||
|
consentOperativo: boolean
|
||||||
|
consentMacroN1: boolean
|
||||||
|
consentVersionId: string
|
||||||
|
}) {
|
||||||
|
// 1. IP hash (server-only)
|
||||||
|
const headersList = await headers()
|
||||||
|
const rawIp = headersList.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'
|
||||||
|
const salt = process.env.IP_HASH_SALT ?? ''
|
||||||
|
const ipHash = createHash('sha256').update(rawIp + salt).digest('hex')
|
||||||
|
|
||||||
|
// 2. Cliente Supabase con anon key (las RLS policies permiten INSERT a anon/authenticated)
|
||||||
|
const supabase = createClient(
|
||||||
|
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||||
|
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
)
|
||||||
|
|
||||||
|
// 3. INSERT consent_record
|
||||||
|
const { data: consent, error: cErr } = await supabase
|
||||||
|
.from('consent_records')
|
||||||
|
.insert({
|
||||||
|
consent_version_id: payload.consentVersionId,
|
||||||
|
granted_scopes: {
|
||||||
|
operativo: payload.consentOperativo,
|
||||||
|
macro_n1: payload.consentMacroN1
|
||||||
|
},
|
||||||
|
granted_at: new Date().toISOString()
|
||||||
|
})
|
||||||
|
.select('id')
|
||||||
|
.single()
|
||||||
|
if (cErr || !consent) return { success: false, error: 'consent_insert_failed' }
|
||||||
|
|
||||||
|
// 4. Extraer qi_* de las respuestas
|
||||||
|
const qi_age_bucket = String(payload.answers['A5'] ?? '')
|
||||||
|
const qi_sector = String(payload.answers['A4'] ?? '')
|
||||||
|
|
||||||
|
// 5. INSERT response
|
||||||
|
const { data: response, error: rErr } = await supabase
|
||||||
|
.from('responses')
|
||||||
|
.insert({
|
||||||
|
survey_id: payload.surveyId,
|
||||||
|
company_id: null, // se setea automáticamente por la survey.org_id en el trigger o app
|
||||||
|
respondent_id: null,
|
||||||
|
ip_hash: ipHash,
|
||||||
|
consent_record_id: consent.id,
|
||||||
|
qi_age_bucket: qi_age_bucket || null,
|
||||||
|
qi_sector: qi_sector || null,
|
||||||
|
qi_zone: null
|
||||||
|
})
|
||||||
|
.select('id')
|
||||||
|
.single()
|
||||||
|
if (rErr || !response) return { success: false, error: 'response_insert_failed' }
|
||||||
|
|
||||||
|
// 6. INSERT answers (bulk, excluir text_long/A2 si están vacíos, siempre excluir A2 separado
|
||||||
|
// ya que va incluido en A1 via GeoWidget)
|
||||||
|
const answerRows = Object.entries(payload.answers)
|
||||||
|
.filter(([code]) => code !== '__consent__') // filtrar meta-campos
|
||||||
|
.map(([code, value]) => ({
|
||||||
|
response_id: response.id,
|
||||||
|
question_id: payload.questionMap[code],
|
||||||
|
value: JSON.stringify(value)
|
||||||
|
}))
|
||||||
|
.filter(row => row.question_id && row.value !== 'null' && row.value !== '""' && row.value !== '[]')
|
||||||
|
|
||||||
|
const { error: aErr } = await supabase.from('answers').insert(answerRows)
|
||||||
|
if (aErr) return { success: false, error: 'answers_insert_failed' }
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
9. En `survey-form.tsx`: al enviar, llamar `submitSurvey(...)`. Si success → mostrar pantalla de
|
||||||
|
agradecimiento/confirmación (reemplaza el resumen actual). Si error → mostrar mensaje de error
|
||||||
|
con opción de reintentar.
|
||||||
|
10. Agregar `IP_HASH_SALT` a `.env.example` (sin valor, solo el nombre).
|
||||||
|
|
||||||
|
## 5. Datos geográficos de Paraguay — constante TypeScript
|
||||||
|
Crear `lib/paraguay-geo.ts` con esta estructura y datos:
|
||||||
|
```typescript
|
||||||
|
export const GEO_DATA: Record<string, string[]> = {
|
||||||
|
"Asunción (Capital)": ["Asunción"],
|
||||||
|
"Alto Paraguay": ["Fuerte Olimpo","Bahía Negra","Carmelo Peralta","La Victoria"],
|
||||||
|
"Alto Paraná": ["Ciudad del Este","Hernandarias","Minga Guazú","Presidente Franco","Minga Porã","Naranjal","Ñacunday","San Alberto","Santa Rita","Tavapy","Yguazú","Juan E. O'Leary","San Cristóbal","Santa Fe del Paraná","Dr. Juan León Mallorquín","Itakyry","Domingo Martínez de Irala"],
|
||||||
|
"Amambay": ["Pedro Juan Caballero","Bella Vista Norte","Capitán Bado","Zanja Pytã"],
|
||||||
|
"Boquerón": ["Filadelfia","Loma Plata","Mariscal Estigarribia","Neuland"],
|
||||||
|
"Caaguazú": ["Coronel Oviedo","Caaguazú","Carayaó","Dr. Juan Manuel Frutos","Mbutuy","Nueva Londres","Raúl Arsenio Oviedo","Repatriación","San Joaquín","San José de los Arroyos","Simón Bolívar","Vaquería","Yhú","José Domingo Ocampos","3 de Febrero","Mcal. Francisco Solano López","Los Cedrales"],
|
||||||
|
"Caazapá": ["Caazapá","Abai","Buena Vista","General Higinio Morínigo","Huber Duré","Maciel","San Juan Nepomuceno","Tavaí","Yegros","Yuty"],
|
||||||
|
"Canindeyú": ["Salto del Guairá","Corpus Christi","Curuguaty","General Francisco Caballero Álvarez","Itanará","Katueté","La Paloma","Nueva Esperanza","Yasy Kañy","Ypejhú"],
|
||||||
|
"Central": ["Areguá","Capiatá","Fernando de la Mora","Guarambaré","Itá","Itauguá","Juan Augusto Saldívar","Lambaré","Limpio","Luque","Mariano Roque Alonso","Nueva Italia","Ñemby","San Antonio","San Lorenzo","Villa Elisa","Villeta","Ypané","Ypacaraí"],
|
||||||
|
"Concepción": ["Concepción","Belén","Horqueta","Loreto","San Lázaro","San Carlos del Apa","Yby Yaú","Azote'y","Sgto. José Félix López"],
|
||||||
|
"Cordillera": ["Caacupé","Altos","Arroyos y Esteros","Caraguatay","Emboscada","Eusebio Ayala","Isla Pucú","Itacurubí de la Cordillera","Juan de Mena","Loma Grande","Mbocayaty del Yhaguy","Nueva Colombia","Pirayú","Primero de Marzo","Tobatí","Valenzuela"],
|
||||||
|
"Guairá": ["Villarrica","Borja","Capitán Mauricio José Troche","Coronel Martínez","Félix Pérez Cardozo","General Eugenio A. Garay","Independencia","Itapé","Iturbe","José Fassardi","Mbocayaty","Natalicio Talavera","Ñumí","San Salvador","Yataity"],
|
||||||
|
"Itapúa": ["Encarnación","Alto Verá","Bella Vista","Cambyretá","Capitán Meza","Capitán Miranda","Carlos A. López","Carmen del Paraná","Coronel Bogado","Cosme","Edelira","Fram","General Artigas","Hohenau","Itapúa Poty","Jesús","La Paz","Leandro Oviedo","Mayor Otaño","Natalio","Nueva Alborada","Obligado","Pirapó","San Cosme y Damián","San Juan del Paraná","San Pedro del Paraná","San Rafael del Paraná","Trinidad","Tomás Romero Pereira"],
|
||||||
|
"Misiones": ["San Juan Bautista","Ayolas","San Ignacio","San Miguel","San Patricio","Santa María","Santa Rosa","Santiago","Villa Florida","Yabebyry"],
|
||||||
|
"Ñeembucú": ["Pilar","Alberdi","Cerrito","Desmochados","General José Eduvigis Díaz","Guazú Cuá","Humaitá","Isla Umbú","Laureles","Mayor José de J. Martínez","Paso de Patria","San Juan Bautista del Ñeembucú","Tacuaras","Villa Franca","Villa Oliva","Villalba"],
|
||||||
|
"Paraguarí": ["Paraguarí","Acahay","Carapeguá","Escobar","General Bernardino Caballero","La Colmena","Mbuyapey","Quiindy","Quyquyhó","San Roque González de Santa Cruz","Sapucaí","Tebicuarymí","Ybycuí","Ybytymí","Yaguarón"],
|
||||||
|
"Presidente Hayes": ["Villa Hayes","Benjamín Aceval","José Falcón","Nanawa","Nueva Asunción","Pozo Colorado","Puerto Pinasco","Teniente Primero Manuel Irala Fernández","Villa del Río"],
|
||||||
|
"San Pedro": ["San Pedro del Ycuamandiyú","Antequera","Choré","General Elizardo Aquino","Guayaibí","Itacurubí del Rosario","Lima","Nueva Germania","Río Verde","San Estanislao (Santaní)","Tacuatí","Unión","Villa del Rosario","Yataity del Norte"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEPARTMENTS = Object.keys(GEO_DATA).sort()
|
||||||
|
export const getCities = (department: string): string[] =>
|
||||||
|
(GEO_DATA[department] ?? []).sort()
|
||||||
|
```
|
||||||
|
Notas sobre los datos: lista basada en fuentes oficiales (INE Paraguay / Wikipedia). Si el director
|
||||||
|
identifica municipios faltantes, se agregan al objeto `GEO_DATA` sin cambio de esquema.
|
||||||
|
|
||||||
|
## 6. company_id en la response
|
||||||
|
El seed tiene `org_id` en la survey. En el Server Action, obtener el `org_id` de la survey para
|
||||||
|
setearlo como `company_id` en el `responses`:
|
||||||
|
```typescript
|
||||||
|
const { data: survey } = await supabase
|
||||||
|
.from('surveys')
|
||||||
|
.select('org_id, consent_version_id, brand_config')
|
||||||
|
.eq('id', payload.surveyId)
|
||||||
|
.single()
|
||||||
|
// Usar survey.org_id como company_id en el INSERT de responses
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Definition of Done
|
||||||
|
- [ ] Dropdowns A1→A2 funcionan en el browser: seleccionar departamento filtra las ciudades.
|
||||||
|
- [ ] A3 (barrio) renderiza como campo de texto.
|
||||||
|
- [ ] A4 tiene opciones Directorio y Gerencia.
|
||||||
|
- [ ] 1.3 tiene opción Tecnología asistiva.
|
||||||
|
- [ ] Header muestra org_name/branch_name/branch_city de brand_config cuando existe.
|
||||||
|
- [ ] `?s=UUID` carga la encuesta correcta; sin parámetro carga la primera live.
|
||||||
|
- [ ] Pantalla de consentimiento aparece antes del formulario con texto honesto (anonimato + no revocación).
|
||||||
|
- [ ] Completar y enviar el formulario escribe en Supabase: 1 consent_record + 1 response + N answers.
|
||||||
|
- [ ] Verificar en Supabase Studio que los registros aparecen.
|
||||||
|
- [ ] `response.ip_hash` no es null ni la IP en texto plano (es el hash).
|
||||||
|
- [ ] `response.company_id` = el org_id de la survey.
|
||||||
|
- [ ] `response.consent_record_id` = el id del consent_record recién creado.
|
||||||
|
- [ ] `answers` tiene una fila por cada pregunta respondida.
|
||||||
|
- [ ] `npm run build` limpio.
|
||||||
|
- [ ] Sin `service_role` ni `IP_HASH_SALT` en código cliente ni en `NEXT_PUBLIC_*`.
|
||||||
|
- [ ] `git diff --name-only HEAD` solo con los archivos autorizados.
|
||||||
|
|
||||||
|
## 8. Validaciones mandatorias
|
||||||
|
- Enviar el formulario → verificar en Supabase Studio (Table Editor) que aparecen filas en
|
||||||
|
`consent_records`, `responses`, `answers`. Si alguna tabla queda vacía → error, no declarar lista.
|
||||||
|
- Enviar dos veces desde el mismo browser → verificar que `ip_hash` es el mismo (deduplicación visible).
|
||||||
|
- El texto del consentimiento menciona explícitamente que la encuesta es anónima y no se puede revocar.
|
||||||
|
- Si CUALQUIER validación falla: NO declarar lista. Reportar y esperar.
|
||||||
|
|
||||||
|
## 9. Qué reportar
|
||||||
|
- Verificado: captura de las filas escritas en consent_records + responses + answers (IDs concretos).
|
||||||
|
- Verificado: ip_hash no es null y es un hash (64 chars hex).
|
||||||
|
- Verificado: company_id del response = org_id de la survey.
|
||||||
|
- Asumidos, hallazgos, decisiones por iniciativa (con nivel).
|
||||||
|
- `git diff --name-only HEAD`.
|
||||||
|
|
||||||
|
## 10. Qué NO hacer
|
||||||
|
- NO exponer `IP_HASH_SALT` ni `service_role` al cliente.
|
||||||
|
- NO poner la IP en texto plano en la base.
|
||||||
|
- NO saltar la pantalla de consentimiento.
|
||||||
|
- NO escribir en la base si el checkbox 1 no fue marcado.
|
||||||
|
- NO modificar las migraciones 001–007 ni las policies de RLS.
|
||||||
|
- NO hardcodear el survey_id en el código (siempre leer del parámetro URL).
|
||||||
|
- Ante conflicto entre restricción y "que funcione": detenerse y reportar.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- Migration 008: fix answers_insert policy
|
||||||
|
-- Root cause: WITH CHECK con EXISTS en responses
|
||||||
|
-- bloqueaba INSERT de anon porque anon no tiene SELECT en responses.
|
||||||
|
-- El FK response_id → responses(id) ya garantiza la integridad referencial.
|
||||||
|
DROP POLICY "answers_insert" ON public.answers;
|
||||||
|
CREATE POLICY "answers_insert" ON public.answers
|
||||||
|
FOR INSERT TO anon, authenticated
|
||||||
|
WITH CHECK (true);
|
||||||
@@ -48,6 +48,11 @@ INSERT INTO public.surveys (
|
|||||||
'20000000-0000-0000-0000-000000000001', 5
|
'20000000-0000-0000-0000-000000000001', 5
|
||||||
) ON CONFLICT (id) DO NOTHING;
|
) ON CONFLICT (id) DO NOTHING;
|
||||||
|
|
||||||
|
-- brand_config: org demo (el director actualiza con datos reales antes de enviar el link)
|
||||||
|
UPDATE public.surveys
|
||||||
|
SET brand_config = '{"org_name":"Empresa Demo","branch_name":"Oficina Central","branch_city":"Asunción"}'::jsonb
|
||||||
|
WHERE id = '30000000-0000-0000-0000-000000000001';
|
||||||
|
|
||||||
-- ── Preguntas: DELETE + INSERT para idempotencia total ────────
|
-- ── Preguntas: DELETE + INSERT para idempotencia total ────────
|
||||||
DELETE FROM public.questions
|
DELETE FROM public.questions
|
||||||
WHERE survey_id = '30000000-0000-0000-0000-000000000001';
|
WHERE survey_id = '30000000-0000-0000-0000-000000000001';
|
||||||
@@ -55,27 +60,69 @@ WHERE survey_id = '30000000-0000-0000-0000-000000000001';
|
|||||||
|
|
||||||
-- ══════════════════════════════════════════════════════════════
|
-- ══════════════════════════════════════════════════════════════
|
||||||
-- SECCIÓN A — Datos Generales (top-level, cuasi-identificadores)
|
-- SECCIÓN A — Datos Generales (top-level, cuasi-identificadores)
|
||||||
-- A1/A2/A3: text_short (texto libre, sin opciones)
|
-- A1=Departamento (single_choice, GeoSelectWidget), A2=Ciudad (single_choice, filtrado client-side)
|
||||||
-- qi_sector ← A4 · qi_age_bucket ← A5
|
-- A3=Barrio (text_short, opcional)
|
||||||
-- qi_city/qi_country ← A2/A1: se agregan como columnas qi en Sprint 3
|
-- qi_sector ← A4 · qi_age_bucket ← A5 · qi_city/qi_country ← Sprint 3
|
||||||
-- ══════════════════════════════════════════════════════════════
|
-- ══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
|
-- A1: Departamento (18 opciones — los 18 departamentos de Paraguay + Capital)
|
||||||
|
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||||
VALUES ('40000000-0000-0000-0000-000000000001','30000000-0000-0000-0000-000000000001',
|
VALUES ('40000000-0000-0000-0000-000000000001','30000000-0000-0000-0000-000000000001',
|
||||||
'A1','text_short','País',1,false,false);
|
'A1','single_choice','Departamento',1,false,false,
|
||||||
|
'[{"value":"Asunción (Capital)","label":"Asunción (Capital)"},
|
||||||
|
{"value":"Alto Paraguay","label":"Alto Paraguay"},
|
||||||
|
{"value":"Alto Paraná","label":"Alto Paraná"},
|
||||||
|
{"value":"Amambay","label":"Amambay"},
|
||||||
|
{"value":"Boquerón","label":"Boquerón"},
|
||||||
|
{"value":"Caaguazú","label":"Caaguazú"},
|
||||||
|
{"value":"Caazapá","label":"Caazapá"},
|
||||||
|
{"value":"Canindeyú","label":"Canindeyú"},
|
||||||
|
{"value":"Central","label":"Central"},
|
||||||
|
{"value":"Concepción","label":"Concepción"},
|
||||||
|
{"value":"Cordillera","label":"Cordillera"},
|
||||||
|
{"value":"Guairá","label":"Guairá"},
|
||||||
|
{"value":"Itapúa","label":"Itapúa"},
|
||||||
|
{"value":"Misiones","label":"Misiones"},
|
||||||
|
{"value":"Ñeembucú","label":"Ñeembucú"},
|
||||||
|
{"value":"Paraguarí","label":"Paraguarí"},
|
||||||
|
{"value":"Presidente Hayes","label":"Presidente Hayes"},
|
||||||
|
{"value":"San Pedro","label":"San Pedro"}]'::jsonb);
|
||||||
|
|
||||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
|
-- A2: Ciudad (todas las ciudades; el GeoSelectWidget filtra client-side por departamento)
|
||||||
|
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||||
VALUES ('40000000-0000-0000-0000-000000000002','30000000-0000-0000-0000-000000000001',
|
VALUES ('40000000-0000-0000-0000-000000000002','30000000-0000-0000-0000-000000000001',
|
||||||
'A2','text_short','Ciudad',2,false,false);
|
'A2','single_choice','Ciudad',2,false,false,
|
||||||
|
'[{"value":"Asunción","label":"Asunción"},
|
||||||
|
{"value":"Fuerte Olimpo","label":"Fuerte Olimpo"},{"value":"Bahía Negra","label":"Bahía Negra"},{"value":"Carmelo Peralta","label":"Carmelo Peralta"},{"value":"La Victoria","label":"La Victoria"},
|
||||||
|
{"value":"Ciudad del Este","label":"Ciudad del Este"},{"value":"Hernandarias","label":"Hernandarias"},{"value":"Minga Guazú","label":"Minga Guazú"},{"value":"Presidente Franco","label":"Presidente Franco"},{"value":"Minga Porã","label":"Minga Porã"},{"value":"Naranjal","label":"Naranjal"},{"value":"Ñacunday","label":"Ñacunday"},{"value":"San Alberto","label":"San Alberto"},{"value":"Santa Rita","label":"Santa Rita"},{"value":"Tavapy","label":"Tavapy"},{"value":"Yguazú","label":"Yguazú"},{"value":"Juan E. O''Leary","label":"Juan E. O''Leary"},{"value":"San Cristóbal","label":"San Cristóbal"},{"value":"Santa Fe del Paraná","label":"Santa Fe del Paraná"},{"value":"Dr. Juan León Mallorquín","label":"Dr. Juan León Mallorquín"},{"value":"Itakyry","label":"Itakyry"},{"value":"Domingo Martínez de Irala","label":"Domingo Martínez de Irala"},
|
||||||
|
{"value":"Pedro Juan Caballero","label":"Pedro Juan Caballero"},{"value":"Bella Vista Norte","label":"Bella Vista Norte"},{"value":"Capitán Bado","label":"Capitán Bado"},{"value":"Zanja Pytã","label":"Zanja Pytã"},
|
||||||
|
{"value":"Filadelfia","label":"Filadelfia"},{"value":"Loma Plata","label":"Loma Plata"},{"value":"Mariscal Estigarribia","label":"Mariscal Estigarribia"},{"value":"Neuland","label":"Neuland"},
|
||||||
|
{"value":"Coronel Oviedo","label":"Coronel Oviedo"},{"value":"Caaguazú","label":"Caaguazú"},{"value":"Carayaó","label":"Carayaó"},{"value":"Dr. Juan Manuel Frutos","label":"Dr. Juan Manuel Frutos"},{"value":"Mbutuy","label":"Mbutuy"},{"value":"Nueva Londres","label":"Nueva Londres"},{"value":"Raúl Arsenio Oviedo","label":"Raúl Arsenio Oviedo"},{"value":"Repatriación","label":"Repatriación"},{"value":"San Joaquín","label":"San Joaquín"},{"value":"San José de los Arroyos","label":"San José de los Arroyos"},{"value":"Simón Bolívar","label":"Simón Bolívar"},{"value":"Vaquería","label":"Vaquería"},{"value":"Yhú","label":"Yhú"},{"value":"José Domingo Ocampos","label":"José Domingo Ocampos"},{"value":"3 de Febrero","label":"3 de Febrero"},{"value":"Mcal. Francisco Solano López","label":"Mcal. Francisco Solano López"},{"value":"Los Cedrales","label":"Los Cedrales"},
|
||||||
|
{"value":"Caazapá","label":"Caazapá"},{"value":"Abai","label":"Abai"},{"value":"Buena Vista","label":"Buena Vista"},{"value":"General Higinio Morínigo","label":"General Higinio Morínigo"},{"value":"Huber Duré","label":"Huber Duré"},{"value":"Maciel","label":"Maciel"},{"value":"San Juan Nepomuceno","label":"San Juan Nepomuceno"},{"value":"Tavaí","label":"Tavaí"},{"value":"Yegros","label":"Yegros"},{"value":"Yuty","label":"Yuty"},
|
||||||
|
{"value":"Salto del Guairá","label":"Salto del Guairá"},{"value":"Corpus Christi","label":"Corpus Christi"},{"value":"Curuguaty","label":"Curuguaty"},{"value":"General Francisco Caballero Álvarez","label":"General Francisco Caballero Álvarez"},{"value":"Itanará","label":"Itanará"},{"value":"Katueté","label":"Katueté"},{"value":"La Paloma","label":"La Paloma"},{"value":"Nueva Esperanza","label":"Nueva Esperanza"},{"value":"Yasy Kañy","label":"Yasy Kañy"},{"value":"Ypejhú","label":"Ypejhú"},
|
||||||
|
{"value":"Areguá","label":"Areguá"},{"value":"Capiatá","label":"Capiatá"},{"value":"Fernando de la Mora","label":"Fernando de la Mora"},{"value":"Guarambaré","label":"Guarambaré"},{"value":"Itá","label":"Itá"},{"value":"Itauguá","label":"Itauguá"},{"value":"Juan Augusto Saldívar","label":"Juan Augusto Saldívar"},{"value":"Lambaré","label":"Lambaré"},{"value":"Limpio","label":"Limpio"},{"value":"Luque","label":"Luque"},{"value":"Mariano Roque Alonso","label":"Mariano Roque Alonso"},{"value":"Nueva Italia","label":"Nueva Italia"},{"value":"Ñemby","label":"Ñemby"},{"value":"San Antonio","label":"San Antonio"},{"value":"San Lorenzo","label":"San Lorenzo"},{"value":"Villa Elisa","label":"Villa Elisa"},{"value":"Villeta","label":"Villeta"},{"value":"Ypané","label":"Ypané"},{"value":"Ypacaraí","label":"Ypacaraí"},
|
||||||
|
{"value":"Concepción","label":"Concepción"},{"value":"Belén","label":"Belén"},{"value":"Horqueta","label":"Horqueta"},{"value":"Loreto","label":"Loreto"},{"value":"San Lázaro","label":"San Lázaro"},{"value":"San Carlos del Apa","label":"San Carlos del Apa"},{"value":"Yby Yaú","label":"Yby Yaú"},{"value":"Azote''y","label":"Azote''y"},{"value":"Sgto. José Félix López","label":"Sgto. José Félix López"},
|
||||||
|
{"value":"Caacupé","label":"Caacupé"},{"value":"Altos","label":"Altos"},{"value":"Arroyos y Esteros","label":"Arroyos y Esteros"},{"value":"Caraguatay","label":"Caraguatay"},{"value":"Emboscada","label":"Emboscada"},{"value":"Eusebio Ayala","label":"Eusebio Ayala"},{"value":"Isla Pucú","label":"Isla Pucú"},{"value":"Itacurubí de la Cordillera","label":"Itacurubí de la Cordillera"},{"value":"Juan de Mena","label":"Juan de Mena"},{"value":"Loma Grande","label":"Loma Grande"},{"value":"Mbocayaty del Yhaguy","label":"Mbocayaty del Yhaguy"},{"value":"Nueva Colombia","label":"Nueva Colombia"},{"value":"Pirayú","label":"Pirayú"},{"value":"Primero de Marzo","label":"Primero de Marzo"},{"value":"Tobatí","label":"Tobatí"},{"value":"Valenzuela","label":"Valenzuela"},
|
||||||
|
{"value":"Villarrica","label":"Villarrica"},{"value":"Borja","label":"Borja"},{"value":"Capitán Mauricio José Troche","label":"Capitán Mauricio José Troche"},{"value":"Coronel Martínez","label":"Coronel Martínez"},{"value":"Félix Pérez Cardozo","label":"Félix Pérez Cardozo"},{"value":"General Eugenio A. Garay","label":"General Eugenio A. Garay"},{"value":"Independencia","label":"Independencia"},{"value":"Itapé","label":"Itapé"},{"value":"Iturbe","label":"Iturbe"},{"value":"José Fassardi","label":"José Fassardi"},{"value":"Mbocayaty","label":"Mbocayaty"},{"value":"Natalicio Talavera","label":"Natalicio Talavera"},{"value":"Ñumí","label":"Ñumí"},{"value":"San Salvador","label":"San Salvador"},{"value":"Yataity","label":"Yataity"},
|
||||||
|
{"value":"Encarnación","label":"Encarnación"},{"value":"Alto Verá","label":"Alto Verá"},{"value":"Bella Vista","label":"Bella Vista"},{"value":"Cambyretá","label":"Cambyretá"},{"value":"Capitán Meza","label":"Capitán Meza"},{"value":"Capitán Miranda","label":"Capitán Miranda"},{"value":"Carlos A. López","label":"Carlos A. López"},{"value":"Carmen del Paraná","label":"Carmen del Paraná"},{"value":"Coronel Bogado","label":"Coronel Bogado"},{"value":"Cosme","label":"Cosme"},{"value":"Edelira","label":"Edelira"},{"value":"Fram","label":"Fram"},{"value":"General Artigas","label":"General Artigas"},{"value":"Hohenau","label":"Hohenau"},{"value":"Itapúa Poty","label":"Itapúa Poty"},{"value":"Jesús","label":"Jesús"},{"value":"La Paz","label":"La Paz"},{"value":"Leandro Oviedo","label":"Leandro Oviedo"},{"value":"Mayor Otaño","label":"Mayor Otaño"},{"value":"Natalio","label":"Natalio"},{"value":"Nueva Alborada","label":"Nueva Alborada"},{"value":"Obligado","label":"Obligado"},{"value":"Pirapó","label":"Pirapó"},{"value":"San Cosme y Damián","label":"San Cosme y Damián"},{"value":"San Juan del Paraná","label":"San Juan del Paraná"},{"value":"San Pedro del Paraná","label":"San Pedro del Paraná"},{"value":"San Rafael del Paraná","label":"San Rafael del Paraná"},{"value":"Trinidad","label":"Trinidad"},{"value":"Tomás Romero Pereira","label":"Tomás Romero Pereira"},
|
||||||
|
{"value":"San Juan Bautista","label":"San Juan Bautista"},{"value":"Ayolas","label":"Ayolas"},{"value":"San Ignacio","label":"San Ignacio"},{"value":"San Miguel","label":"San Miguel"},{"value":"San Patricio","label":"San Patricio"},{"value":"Santa María","label":"Santa María"},{"value":"Santa Rosa","label":"Santa Rosa"},{"value":"Santiago","label":"Santiago"},{"value":"Villa Florida","label":"Villa Florida"},{"value":"Yabebyry","label":"Yabebyry"},
|
||||||
|
{"value":"Pilar","label":"Pilar"},{"value":"Alberdi","label":"Alberdi"},{"value":"Cerrito","label":"Cerrito"},{"value":"Desmochados","label":"Desmochados"},{"value":"General José Eduvigis Díaz","label":"General José Eduvigis Díaz"},{"value":"Guazú Cuá","label":"Guazú Cuá"},{"value":"Humaitá","label":"Humaitá"},{"value":"Isla Umbú","label":"Isla Umbú"},{"value":"Laureles","label":"Laureles"},{"value":"Mayor José de J. Martínez","label":"Mayor José de J. Martínez"},{"value":"Paso de Patria","label":"Paso de Patria"},{"value":"San Juan Bautista del Ñeembucú","label":"San Juan Bautista del Ñeembucú"},{"value":"Tacuaras","label":"Tacuaras"},{"value":"Villa Franca","label":"Villa Franca"},{"value":"Villa Oliva","label":"Villa Oliva"},{"value":"Villalba","label":"Villalba"},
|
||||||
|
{"value":"Paraguarí","label":"Paraguarí"},{"value":"Acahay","label":"Acahay"},{"value":"Carapeguá","label":"Carapeguá"},{"value":"Escobar","label":"Escobar"},{"value":"General Bernardino Caballero","label":"General Bernardino Caballero"},{"value":"La Colmena","label":"La Colmena"},{"value":"Mbuyapey","label":"Mbuyapey"},{"value":"Quiindy","label":"Quiindy"},{"value":"Quyquyhó","label":"Quyquyhó"},{"value":"San Roque González de Santa Cruz","label":"San Roque González de Santa Cruz"},{"value":"Sapucaí","label":"Sapucaí"},{"value":"Tebicuarymí","label":"Tebicuarymí"},{"value":"Ybycuí","label":"Ybycuí"},{"value":"Ybytymí","label":"Ybytymí"},{"value":"Yaguarón","label":"Yaguarón"},
|
||||||
|
{"value":"Villa Hayes","label":"Villa Hayes"},{"value":"Benjamín Aceval","label":"Benjamín Aceval"},{"value":"José Falcón","label":"José Falcón"},{"value":"Nanawa","label":"Nanawa"},{"value":"Nueva Asunción","label":"Nueva Asunción"},{"value":"Pozo Colorado","label":"Pozo Colorado"},{"value":"Puerto Pinasco","label":"Puerto Pinasco"},{"value":"Teniente Primero Manuel Irala Fernández","label":"Teniente Primero Manuel Irala Fernández"},{"value":"Villa del Río","label":"Villa del Río"},
|
||||||
|
{"value":"San Pedro del Ycuamandiyú","label":"San Pedro del Ycuamandiyú"},{"value":"Antequera","label":"Antequera"},{"value":"Choré","label":"Choré"},{"value":"General Elizardo Aquino","label":"General Elizardo Aquino"},{"value":"Guayaibí","label":"Guayaibí"},{"value":"Itacurubí del Rosario","label":"Itacurubí del Rosario"},{"value":"Lima","label":"Lima"},{"value":"Nueva Germania","label":"Nueva Germania"},{"value":"Río Verde","label":"Río Verde"},{"value":"San Estanislao (Santaní)","label":"San Estanislao (Santaní)"},{"value":"Tacuatí","label":"Tacuatí"},{"value":"Unión","label":"Unión"},{"value":"Villa del Rosario","label":"Villa del Rosario"},{"value":"Yataity del Norte","label":"Yataity del Norte"}
|
||||||
|
]'::jsonb);
|
||||||
|
|
||||||
|
-- A3: Barrio (text_short, opcional — antes era "Sucursal o sede")
|
||||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
|
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required)
|
||||||
VALUES ('40000000-0000-0000-0000-000000000003','30000000-0000-0000-0000-000000000001',
|
VALUES ('40000000-0000-0000-0000-000000000003','30000000-0000-0000-0000-000000000001',
|
||||||
'A3','text_short','Sucursal o sede',3,false,false);
|
'A3','text_short','¿En qué barrio vivís? (opcional)',3,false,false);
|
||||||
|
|
||||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||||
VALUES ('40000000-0000-0000-0000-000000000004','30000000-0000-0000-0000-000000000001',
|
VALUES ('40000000-0000-0000-0000-000000000004','30000000-0000-0000-0000-000000000001',
|
||||||
'A4','single_choice','¿En qué área o gerencia trabajás?',4,false,false,
|
'A4','single_choice','¿En qué área o gerencia trabajás?',4,false,false,
|
||||||
'[{"value":"Operaciones/Producción","label":"Operaciones/Producción"},
|
'[{"value":"Directorio","label":"Directorio"},
|
||||||
|
{"value":"Gerencia","label":"Gerencia"},
|
||||||
|
{"value":"Operaciones/Producción","label":"Operaciones/Producción"},
|
||||||
{"value":"Comercial/Ventas","label":"Comercial/Ventas"},
|
{"value":"Comercial/Ventas","label":"Comercial/Ventas"},
|
||||||
{"value":"Administración/Finanzas","label":"Administración/Finanzas"},
|
{"value":"Administración/Finanzas","label":"Administración/Finanzas"},
|
||||||
{"value":"Recursos Humanos/Cultura","label":"Recursos Humanos/Cultura"},
|
{"value":"Recursos Humanos/Cultura","label":"Recursos Humanos/Cultura"},
|
||||||
@@ -146,6 +193,7 @@ VALUES ('40000000-0000-0000-0000-000000000010','30000000-0000-0000-0000-00000000
|
|||||||
{"value":"Andador","label":"Andador"},
|
{"value":"Andador","label":"Andador"},
|
||||||
{"value":"Muletas","label":"Muletas"},
|
{"value":"Muletas","label":"Muletas"},
|
||||||
{"value":"Prótesis","label":"Prótesis"},
|
{"value":"Prótesis","label":"Prótesis"},
|
||||||
|
{"value":"Tecnología asistiva","label":"Tecnología asistiva"},
|
||||||
{"value":"No utilizo","label":"No utilizo"}]'::jsonb,
|
{"value":"No utilizo","label":"No utilizo"}]'::jsonb,
|
||||||
'[{"if_question":"1.1","op":"eq","value":"Sí","action":"show"}]'::jsonb);
|
'[{"if_question":"1.1","op":"eq","value":"Sí","action":"show"}]'::jsonb);
|
||||||
|
|
||||||
|
|||||||