Selaa lähdekoodia

funcao para abrir wpp com mensagem pre preenchida para msg da serprati

Gustavo Zanatta 1 kuukausi sitten
vanhempi
commit
e58f78e673

+ 152 - 136
src/i18n/locales/en.json

@@ -4,13 +4,27 @@
       "description": "Manage the products available in the store"
     },
     "associado": {
-      "profile": { "description": "View and edit your personal data and dependents" },
-      "carteirinha": { "description": "Your digital membership card with QR Code" },
-      "convenios": { "description": "Browse available partners and agreements" },
-      "loja": { "description": "Browse available store items" },
-      "interesses": { "description": "Items you marked as interest" },
-      "agendamentos": { "description": "Request and track your appointments" },
-      "notificacoes": { "description": "Your notifications and alerts" }
+      "profile": {
+        "description": "View and edit your personal data and dependents"
+      },
+      "carteirinha": {
+        "description": "Your digital membership card with QR Code"
+      },
+      "convenios": {
+        "description": "Browse available partners and agreements"
+      },
+      "loja": {
+        "description": "Browse available store items"
+      },
+      "interesses": {
+        "description": "Items you marked as interest"
+      },
+      "agendamentos": {
+        "description": "Request and track your appointments"
+      },
+      "notificacoes": {
+        "description": "Your notifications and alerts"
+      }
     },
     "gestao_associados": {
       "description": "View, edit, and add members to the system"
@@ -493,8 +507,7 @@
       "pt": "Português",
       "en": "English",
       "es": "Español"
-    },
-    "search_placeholder": "Search Members"
+    }
   },
   "access_log": {
     "title": "Access Logs",
@@ -571,149 +584,152 @@
     }
   },
   "loja": {
-    "product":                    "Product",
-    "products":                   "Products",
-    "supplier_price":             "Supplier Price",
-    "supplier":                   "Supplier",
-    "stock":                       "Stock",
-    "interests":                  "Interested",
-    "interested_btn":             "INTERESTED",
-    "interested_in":              "Interested in",
-    "media":                      "Media",
-    "add_media":                  "Add Media",
-    "uploading_media":            "Uploading media...",
-    "activate":                   "Activate",
-    "deactivate":                 "Deactivate",
-    "variation":                  "Variation",
-    "variation_tamanho":          "Size",
-    "variation_cor":              "Color",
-    "variation_modelo":           "Model",
-    "variation_label":            "Name",
-    "variation_value":            "Value (R$)",
-    "variation_stock":            "Stock",
-    "variation_cor_placeholder":  "E.g.: Purple, White...",
+    "product": "Product",
+    "products": "Products",
+    "supplier_price": "Supplier Price",
+    "supplier": "Supplier",
+    "stock": "Stock",
+    "interests": "Interested",
+    "interested_btn": "INTERESTED",
+    "interested_in": "Interested in",
+    "media": "Media",
+    "add_media": "Add Media",
+    "uploading_media": "Uploading media...",
+    "activate": "Activate",
+    "deactivate": "Deactivate",
+    "variation": "Variation",
+    "variation_tamanho": "Size",
+    "variation_cor": "Color",
+    "variation_modelo": "Model",
+    "variation_label": "Name",
+    "variation_value": "Value (R$)",
+    "variation_stock": "Stock",
+    "variation_cor_placeholder": "E.g.: Purple, White...",
     "variation_modelo_placeholder": "E.g.: Associate, Premium...",
-    "variation_empty":            "No variation added",
-    "add_variation":              "Add",
-    "filter_all":                 "All",
-    "filter_recent":              "Recent",
-    "filter_others":              "Others",
-    "btn_interested":             "I'm interested",
-    "btn_want":                   "I want"
+    "variation_empty": "No variation added",
+    "add_variation": "Add",
+    "filter_all": "All",
+    "filter_recent": "Recent",
+    "filter_others": "Others",
+    "btn_interested": "I'm interested",
+    "btn_want": "I want",
+    "whatsapp_dialog_title": "Talk on WhatsApp",
+    "whatsapp_message": "Hello, I am {nome} and I am interested in this store item: {item}{variacao}.",
+    "whatsapp_btn_send": "Open WhatsApp"
   },
   "parceiro": {
-    "category":                "Category",
-    "company_name":            "Company Name",
-    "responsible":             "Responsible",
-    "discount_percentage":     "Discount (%)",
-    "logo":                    "Logo",
-    "website":                 "Website",
-    "zip_code":                "ZIP Code",
-    "address":                 "Address",
-    "neighborhood":            "Neighborhood",
-    "working_hours":           "Working Hours",
+    "category": "Category",
+    "company_name": "Company Name",
+    "responsible": "Responsible",
+    "discount_percentage": "Discount (%)",
+    "logo": "Logo",
+    "website": "Website",
+    "zip_code": "ZIP Code",
+    "address": "Address",
+    "neighborhood": "Neighborhood",
+    "working_hours": "Working Hours",
     "working_hours_placeholder": "e.g. Mon-Fri 8am-6pm, Sat 8am-12pm",
-    "contract_start":          "Contract Start",
-    "contract_end":            "Contract End",
-    "contract_files":          "Contract Files",
-    "add_file":                "Add File",
-    "services":                "Services",
-    "service":                 "Service",
-    "service_category":        "Service Category",
-    "service_number":          "Service Number",
-    "price":                   "Price",
-    "associate_price":         "Associate Price",
-    "supplier_price":          "Supplier Price",
-    "requires_scheduling":     "Requires Scheduling",
-    "search_placeholder":      "Search for service",
-    "import_parceiros":        "Partners",
-    "import_convenios":        "Medical Agreements",
+    "contract_start": "Contract Start",
+    "contract_end": "Contract End",
+    "contract_files": "Contract Files",
+    "add_file": "Add File",
+    "services": "Services",
+    "service": "Service",
+    "service_category": "Service Category",
+    "service_number": "Service Number",
+    "price": "Price",
+    "associate_price": "Associate Price",
+    "supplier_price": "Supplier Price",
+    "requires_scheduling": "Requires Scheduling",
+    "search_placeholder": "Search for service",
+    "import_parceiros": "Partners",
+    "import_convenios": "Medical Agreements",
     "import_parceiros_result": "{created} created · {updated} updated · {inactivated} inactivated",
     "import_convenios_result": "{partners_created} clinics created · {services_created} services created · {partners_inactivated} inactivated",
-    "import_processing":       "Import is still processing. Please refresh the page in a moment.",
-    "cadastro_title":          "Partner Registration",
-    "cadastro_parceiro":       "Partner Registration",
-    "dados_parceiro":          "Partner Data",
-    "tab_dados":               "Company Data",
-    "tab_contato":             "Contact",
-    "tab_endereco":            "Address",
-    "tab_horario":             "Schedule & Contract",
-    "tab_servicos":            "My Services",
-    "usuario_parceiro":        "Partner User",
-    "linked_user":             "Linked User",
-    "home":                    "Home",
+    "import_processing": "Import is still processing. Please refresh the page in a moment.",
+    "cadastro_title": "Partner Registration",
+    "cadastro_parceiro": "Partner Registration",
+    "dados_parceiro": "Partner Data",
+    "tab_dados": "Company Data",
+    "tab_contato": "Contact",
+    "tab_endereco": "Address",
+    "tab_horario": "Schedule & Contract",
+    "tab_servicos": "My Services",
+    "usuario_parceiro": "Partner User",
+    "linked_user": "Linked User",
+    "home": "Home",
     "dashboard": {
-      "title":         "Dashboard",
+      "title": "Dashboard",
       "authorization": "Pending Authorizations",
-      "scheduling":    "Appointments",
-      "completed":     "Completed",
-      "not_authorized":"Not Authorized"
+      "scheduling": "Appointments",
+      "completed": "Completed",
+      "not_authorized": "Not Authorized"
     }
   },
   "agendamento": {
-    "associado":                  "Associate",
-    "solicitar":                  "Request",
-    "nova_solicitacao":           "New Request",
-    "visao_geral":                "Overview",
-    "aprovados_automaticamente":  "Auto Approved",
-    "definir_data_hora":          "Set date and time",
-    "confirm_reject":             "Confirm rejection of this appointment?",
+    "associado": "Associate",
+    "solicitar": "Request",
+    "nova_solicitacao": "New Request",
+    "visao_geral": "Overview",
+    "aprovados_automaticamente": "Auto Approved",
+    "definir_data_hora": "Set date and time",
+    "confirm_reject": "Confirm rejection of this appointment?",
     "status": {
-      "pendente":   "Pending",
+      "pendente": "Pending",
       "confirmado": "Confirmed",
-      "recusado":   "Rejected",
-      "cancelado":  "Cancelled",
-      "concluido":  "Completed"
+      "recusado": "Rejected",
+      "cancelado": "Cancelled",
+      "concluido": "Completed"
     },
     "col": {
-      "pedido":     "Order",
-      "parceiro":   "Partner",
-      "servico":    "Service",
-      "solicitacao":"Request"
+      "pedido": "Order",
+      "parceiro": "Partner",
+      "servico": "Service",
+      "solicitacao": "Request"
     }
   },
   "notification": {
-    "empty":                "No notifications at the moment",
-    "new":                  "New",
-    "history":              "History",
-    "title_label":          "Title",
-    "title_placeholder":    "Notification title",
-    "message_label":        "Message",
-    "message_placeholder":  "Notification message",
-    "recipients":           "Recipients",
-    "by_position":          "By Position",
-    "by_sector":            "By Sector",
-    "media":                "Media",
-    "send":                 "Send",
-    "all":                  "All",
-    "recipient_associado":  "Associates",
-    "recipient_parceiro":   "Partners",
-    "details":              "Details",
-    "sent_to":              "Sent to {count} user(s)",
-    "seen_by":              "Seen by {count} user(s)",
-    "pending_read_title":   "Pending Notifications",
+    "empty": "No notifications at the moment",
+    "new": "New",
+    "history": "History",
+    "title_label": "Title",
+    "title_placeholder": "Notification title",
+    "message_label": "Message",
+    "message_placeholder": "Notification message",
+    "recipients": "Recipients",
+    "by_position": "By Position",
+    "by_sector": "By Sector",
+    "media": "Media",
+    "send": "Send",
+    "all": "All",
+    "recipient_associado": "Associates",
+    "recipient_parceiro": "Partners",
+    "details": "Details",
+    "sent_to": "Sent to {count} user(s)",
+    "seen_by": "Seen by {count} user(s)",
+    "pending_read_title": "Pending Notifications",
     "pending_read_subtitle": "You have unread notifications. Read all of them to continue.",
-    "pending_read_hint":    "Click on each notification to mark it as read.",
-    "pending_read_close":   "Close"
+    "pending_read_hint": "Click on each notification to mark it as read.",
+    "pending_read_close": "Close"
   },
   "associate_validation": {
-    "title":               "Validate Card",
-    "qr_code":             "QR Code",
-    "description":         "Search the associate by badge or CPF",
-    "search_placeholder":  "Badge or CPF",
-    "search":              "Search",
-    "associate_found":     "Associate Found",
-    "name":                "Name",
-    "cpf":                 "CPF",
-    "registration":        "Registration",
-    "expiry_date":         "Expiry Date",
-    "no_photo":            "No photo"
+    "title": "Validate Card",
+    "qr_code": "QR Code",
+    "description": "Search the associate by badge or CPF",
+    "search_placeholder": "Badge or CPF",
+    "search": "Search",
+    "associate_found": "Associate Found",
+    "name": "Name",
+    "cpf": "CPF",
+    "registration": "Registration",
+    "expiry_date": "Expiry Date",
+    "no_photo": "No photo"
   },
   "relatorio": {
-    "exportar_excel":    "Export Excel",
-    "novos_associados":  "New Associates",
-    "contatos":          "Contacts",
-    "exclusoes_mes":     "Monthly Exclusions",
+    "exportar_excel": "Export Excel",
+    "novos_associados": "New Associates",
+    "contatos": "Contacts",
+    "exclusoes_mes": "Monthly Exclusions",
     "col": {
       "cadastro": "Registration",
       "exclusao": "Exclusion"
@@ -721,12 +737,12 @@
   },
   "import_log": {
     "history_title": "Import History",
-    "date_time":     "Date/Time",
-    "imported_by":   "Imported by",
-    "total":         "Total",
-    "created":       "New",
-    "updated":       "Updated",
-    "inactivated":   "Inactivated",
-    "no_history":    "No imports recorded"
+    "date_time": "Date/Time",
+    "imported_by": "Imported by",
+    "total": "Total",
+    "created": "New",
+    "updated": "Updated",
+    "inactivated": "Inactivated",
+    "no_history": "No imports recorded"
   }
 }

+ 152 - 136
src/i18n/locales/es.json

@@ -4,13 +4,27 @@
       "description": "Gestione los productos disponibles en la tienda"
     },
     "associado": {
-      "profile": { "description": "Visualice y edite sus datos personales y dependientes" },
-      "carteirinha": { "description": "Su tarjeta digital con código QR de identificación" },
-      "convenios": { "description": "Consulte los socios y convenios disponibles" },
-      "loja": { "description": "Consulte los artículos disponibles en la tienda" },
-      "interesses": { "description": "Artículos que marcó como interés" },
-      "agendamentos": { "description": "Solicite y realice seguimiento de sus citas" },
-      "notificacoes": { "description": "Sus notificaciones y avisos" }
+      "profile": {
+        "description": "Visualice y edite sus datos personales y dependientes"
+      },
+      "carteirinha": {
+        "description": "Su tarjeta digital con código QR de identificación"
+      },
+      "convenios": {
+        "description": "Consulte los socios y convenios disponibles"
+      },
+      "loja": {
+        "description": "Consulte los artículos disponibles en la tienda"
+      },
+      "interesses": {
+        "description": "Artículos que marcó como interés"
+      },
+      "agendamentos": {
+        "description": "Solicite y realice seguimiento de sus citas"
+      },
+      "notificacoes": {
+        "description": "Sus notificaciones y avisos"
+      }
     },
     "gestao_associados": {
       "description": "Consulte, edite y agregue los asociados del sistema"
@@ -435,7 +449,7 @@
     "import_associados": "Asociados",
     "import_sync_result": "{created} creados · {updated} actualizados · {inactivated} inactivados",
     "import_processing": "La importación está en progreso. Actualice la página en unos instantes.",
-    "search_placeholder": "Buscar Asociados",
+    "search_placeholder": "Buscar por asociados",
     "no_dependents": "Ningún dependiente registrado",
     "remove_photo": "¿Deseas eliminar tu foto de perfil?",
     "kinship": "Parentesco",
@@ -494,8 +508,7 @@
       "pt": "Português",
       "en": "English",
       "es": "Español"
-    },
-    "search_placeholder": "Buscar por asociados"
+    }
   },
   "access_log": {
     "title": "Registros de Acceso",
@@ -572,148 +585,151 @@
     }
   },
   "loja": {
-    "product":                    "Producto",
-    "products":                   "Productos",
-    "supplier_price":             "Precio Proveedor",
-    "supplier":                   "Proveedor",
-    "interests":                  "Interesados",
-    "interested_btn":             "INTERESADOS",
-    "interested_in":              "Interesados en",
-    "media":                      "Medios",
-    "add_media":                  "Agregar Medio",
-    "uploading_media":            "Subiendo medio...",
-    "activate":                   "Activar",
-    "deactivate":                 "Desactivar",
-    "variation":                  "Variación",
-    "variation_tamanho":          "Talla",
-    "variation_cor":              "Color",
-    "variation_modelo":           "Modelo",
-    "variation_label":            "Nombre",
-    "variation_value":            "Valor (R$)",
-    "variation_stock":            "Stock",
-    "variation_cor_placeholder":  "Ej: Morado, Blanco...",
+    "product": "Producto",
+    "products": "Productos",
+    "supplier_price": "Precio Proveedor",
+    "supplier": "Proveedor",
+    "interests": "Interesados",
+    "interested_btn": "INTERESADOS",
+    "interested_in": "Interesados en",
+    "media": "Medios",
+    "add_media": "Agregar Medio",
+    "uploading_media": "Subiendo medio...",
+    "activate": "Activar",
+    "deactivate": "Desactivar",
+    "variation": "Variación",
+    "variation_tamanho": "Talla",
+    "variation_cor": "Color",
+    "variation_modelo": "Modelo",
+    "variation_label": "Nombre",
+    "variation_value": "Valor (R$)",
+    "variation_stock": "Stock",
+    "variation_cor_placeholder": "Ej: Morado, Blanco...",
     "variation_modelo_placeholder": "Ej: Asociado, Premium...",
-    "variation_empty":            "Sin variaciones agregadas",
-    "add_variation":              "Agregar",
-    "filter_all":                 "Todos",
-    "filter_recent":              "Recientes",
-    "filter_others":              "Otros",
-    "btn_interested":             "Ya me interesa",
-    "btn_want":                   "Lo quiero"
+    "variation_empty": "Sin variaciones agregadas",
+    "add_variation": "Agregar",
+    "filter_all": "Todos",
+    "filter_recent": "Recientes",
+    "filter_others": "Otros",
+    "btn_interested": "Ya me interesa",
+    "btn_want": "Lo quiero",
+    "whatsapp_dialog_title": "Hablar por WhatsApp",
+    "whatsapp_message": "Hola, soy {nome} y tengo interés en este artículo de la tienda: {item}{variacao}.",
+    "whatsapp_btn_send": "Abrir WhatsApp"
   },
   "parceiro": {
-    "category":                "Categoría",
-    "company_name":            "Nombre de la Empresa",
-    "responsible":             "Responsable",
-    "discount_percentage":     "Descuento (%)",
-    "logo":                    "Logo",
-    "website":                 "Sitio Web",
-    "zip_code":                "Código Postal",
-    "address":                 "Dirección",
-    "neighborhood":            "Barrio",
-    "working_hours":           "Horario de Atención",
+    "category": "Categoría",
+    "company_name": "Nombre de la Empresa",
+    "responsible": "Responsable",
+    "discount_percentage": "Descuento (%)",
+    "logo": "Logo",
+    "website": "Sitio Web",
+    "zip_code": "Código Postal",
+    "address": "Dirección",
+    "neighborhood": "Barrio",
+    "working_hours": "Horario de Atención",
     "working_hours_placeholder": "Ej: Lun-Vie 8h-18h, Sáb 8h-12h",
-    "contract_start":          "Inicio del Contrato",
-    "contract_end":            "Fin del Contrato",
-    "contract_files":          "Archivos del Contrato",
-    "add_file":                "Agregar Archivo",
-    "services":                "Servicios",
-    "service":                 "Servicio",
-    "service_category":        "Categoría del Servicio",
-    "service_number":          "Número del Servicio",
-    "price":                   "Precio",
-    "associate_price":         "Precio Asociado",
-    "supplier_price":          "Precio Proveedor",
-    "requires_scheduling":     "Requiere Programación",
-    "search_placeholder":      "Buscar por servicio",
-    "import_parceiros":        "Socios",
-    "import_convenios":        "Convenios Médicos",
+    "contract_start": "Inicio del Contrato",
+    "contract_end": "Fin del Contrato",
+    "contract_files": "Archivos del Contrato",
+    "add_file": "Agregar Archivo",
+    "services": "Servicios",
+    "service": "Servicio",
+    "service_category": "Categoría del Servicio",
+    "service_number": "Número del Servicio",
+    "price": "Precio",
+    "associate_price": "Precio Asociado",
+    "supplier_price": "Precio Proveedor",
+    "requires_scheduling": "Requiere Programación",
+    "search_placeholder": "Buscar por servicio",
+    "import_parceiros": "Socios",
+    "import_convenios": "Convenios Médicos",
     "import_parceiros_result": "{created} creados · {updated} actualizados · {inactivated} inactivados",
     "import_convenios_result": "{partners_created} clínicas creadas · {services_created} servicios creados · {partners_inactivated} inactivados",
-    "import_processing":       "La importación está en progreso. Actualice la página en unos instantes.",
-    "cadastro_title":          "Registro de Socio",
-    "cadastro_parceiro":       "Registro de Socio",
-    "dados_parceiro":          "Datos del Socio",
-    "tab_dados":               "Datos de la Empresa",
-    "tab_contato":             "Contacto",
-    "tab_endereco":            "Dirección",
-    "tab_horario":             "Horario y Contrato",
-    "tab_servicos":            "Mis Servicios",
-    "usuario_parceiro":        "Usuario Socio",
-    "linked_user":             "Usuario Vinculado",
-    "home":                    "Inicio",
+    "import_processing": "La importación está en progreso. Actualice la página en unos instantes.",
+    "cadastro_title": "Registro de Socio",
+    "cadastro_parceiro": "Registro de Socio",
+    "dados_parceiro": "Datos del Socio",
+    "tab_dados": "Datos de la Empresa",
+    "tab_contato": "Contacto",
+    "tab_endereco": "Dirección",
+    "tab_horario": "Horario y Contrato",
+    "tab_servicos": "Mis Servicios",
+    "usuario_parceiro": "Usuario Socio",
+    "linked_user": "Usuario Vinculado",
+    "home": "Inicio",
     "dashboard": {
-      "title":         "Dashboard",
+      "title": "Dashboard",
       "authorization": "Autorizaciones Pendientes",
-      "scheduling":    "Citas",
-      "completed":     "Completados",
-      "not_authorized":"No Autorizados"
+      "scheduling": "Citas",
+      "completed": "Completados",
+      "not_authorized": "No Autorizados"
     }
   },
   "agendamento": {
-    "associado":                  "Asociado",
-    "solicitar":                  "Solicitar",
-    "nova_solicitacao":           "Nueva Solicitud",
-    "visao_geral":                "Vista General",
-    "aprovados_automaticamente":  "Aprobados Automáticamente",
-    "definir_data_hora":          "Definir fecha y hora",
-    "confirm_reject":             "¿Confirmar rechazo de esta cita?",
+    "associado": "Asociado",
+    "solicitar": "Solicitar",
+    "nova_solicitacao": "Nueva Solicitud",
+    "visao_geral": "Vista General",
+    "aprovados_automaticamente": "Aprobados Automáticamente",
+    "definir_data_hora": "Definir fecha y hora",
+    "confirm_reject": "¿Confirmar rechazo de esta cita?",
     "status": {
-      "pendente":   "Pendiente",
+      "pendente": "Pendiente",
       "confirmado": "Confirmado",
-      "recusado":   "Rechazado",
-      "cancelado":  "Cancelado",
-      "concluido":  "Completado"
+      "recusado": "Rechazado",
+      "cancelado": "Cancelado",
+      "concluido": "Completado"
     },
     "col": {
-      "pedido":     "Pedido",
-      "parceiro":   "Socio",
-      "servico":    "Servicio",
-      "solicitacao":"Solicitud"
+      "pedido": "Pedido",
+      "parceiro": "Socio",
+      "servico": "Servicio",
+      "solicitacao": "Solicitud"
     }
   },
   "notification": {
-    "empty":                "Sin notificaciones en este momento",
-    "new":                  "Nueva",
-    "history":              "Historial",
-    "title_label":          "Título",
-    "title_placeholder":    "Título de la notificación",
-    "message_label":        "Mensaje",
-    "message_placeholder":  "Mensaje de la notificación",
-    "recipients":           "Destinatarios",
-    "by_position":          "Por Cargo",
-    "by_sector":            "Por Sector",
-    "media":                "Multimedia",
-    "send":                 "Enviar",
-    "all":                  "Todos",
-    "recipient_associado":  "Asociados",
-    "recipient_parceiro":   "Socios",
-    "details":              "Detalles",
-    "sent_to":              "Enviado a {count} usuario(s)",
-    "seen_by":              "Visto por {count} usuario(s)",
-    "pending_read_title":   "Notificaciones Pendientes",
+    "empty": "Sin notificaciones en este momento",
+    "new": "Nueva",
+    "history": "Historial",
+    "title_label": "Título",
+    "title_placeholder": "Título de la notificación",
+    "message_label": "Mensaje",
+    "message_placeholder": "Mensaje de la notificación",
+    "recipients": "Destinatarios",
+    "by_position": "Por Cargo",
+    "by_sector": "Por Sector",
+    "media": "Multimedia",
+    "send": "Enviar",
+    "all": "Todos",
+    "recipient_associado": "Asociados",
+    "recipient_parceiro": "Socios",
+    "details": "Detalles",
+    "sent_to": "Enviado a {count} usuario(s)",
+    "seen_by": "Visto por {count} usuario(s)",
+    "pending_read_title": "Notificaciones Pendientes",
     "pending_read_subtitle": "Tiene notificaciones no leídas. Léalas todas para continuar.",
-    "pending_read_hint":    "Haga clic en cada notificación para marcarla como leída.",
-    "pending_read_close":   "Cerrar"
+    "pending_read_hint": "Haga clic en cada notificación para marcarla como leída.",
+    "pending_read_close": "Cerrar"
   },
   "associate_validation": {
-    "title":               "Validar Tarjeta",
-    "qr_code":             "Código QR",
-    "description":         "Busque el asociado por credencial o CPF",
-    "search_placeholder":  "Credencial o CPF",
-    "search":              "Buscar",
-    "associate_found":     "Asociado Encontrado",
-    "name":                "Nombre",
-    "cpf":                 "CPF",
-    "registration":        "Matrícula",
-    "expiry_date":         "Vencimiento",
-    "no_photo":            "Sin foto"
+    "title": "Validar Tarjeta",
+    "qr_code": "Código QR",
+    "description": "Busque el asociado por credencial o CPF",
+    "search_placeholder": "Credencial o CPF",
+    "search": "Buscar",
+    "associate_found": "Asociado Encontrado",
+    "name": "Nombre",
+    "cpf": "CPF",
+    "registration": "Matrícula",
+    "expiry_date": "Vencimiento",
+    "no_photo": "Sin foto"
   },
   "relatorio": {
-    "exportar_excel":    "Exportar Excel",
-    "novos_associados":  "Nuevos Asociados",
-    "contatos":          "Contactos",
-    "exclusoes_mes":     "Exclusiones del Mes",
+    "exportar_excel": "Exportar Excel",
+    "novos_associados": "Nuevos Asociados",
+    "contatos": "Contactos",
+    "exclusoes_mes": "Exclusiones del Mes",
     "col": {
       "cadastro": "Registro",
       "exclusao": "Exclusión"
@@ -721,12 +737,12 @@
   },
   "import_log": {
     "history_title": "Historial de Importaciones",
-    "date_time":     "Fecha/Hora",
-    "imported_by":   "Importado por",
-    "total":         "Total",
-    "created":       "Nuevos",
-    "updated":       "Actualizados",
-    "inactivated":   "Desactivados",
-    "no_history":    "Ninguna importación registrada"
+    "date_time": "Fecha/Hora",
+    "imported_by": "Importado por",
+    "total": "Total",
+    "created": "Nuevos",
+    "updated": "Actualizados",
+    "inactivated": "Desactivados",
+    "no_history": "Ninguna importación registrada"
   }
 }

+ 153 - 137
src/i18n/locales/pt.json

@@ -4,13 +4,27 @@
       "description": "Gerencie os produtos disponíveis na loja"
     },
     "associado": {
-      "profile": { "description": "Visualize e edite seus dados pessoais e dependentes" },
-      "carteirinha": { "description": "Sua carteira digital com QR Code de identificação" },
-      "convenios": { "description": "Confira os parceiros e convênios disponíveis para você" },
-      "loja": { "description": "Confira os itens disponíveis na loja" },
-      "interesses": { "description": "Itens que você marcou como interesse" },
-      "agendamentos": { "description": "Solicite e acompanhe seus agendamentos" },
-      "notificacoes": { "description": "Suas notificações e avisos" }
+      "profile": {
+        "description": "Visualize e edite seus dados pessoais e dependentes"
+      },
+      "carteirinha": {
+        "description": "Sua carteira digital com QR Code de identificação"
+      },
+      "convenios": {
+        "description": "Confira os parceiros e convênios disponíveis para você"
+      },
+      "loja": {
+        "description": "Confira os itens disponíveis na loja"
+      },
+      "interesses": {
+        "description": "Itens que você marcou como interesse"
+      },
+      "agendamentos": {
+        "description": "Solicite e acompanhe seus agendamentos"
+      },
+      "notificacoes": {
+        "description": "Suas notificações e avisos"
+      }
     },
     "gestao_associados": {
       "description": "Consulte, edite e adicione os associados do sistema"
@@ -435,7 +449,7 @@
     "import_associados": "Associados",
     "import_sync_result": "{created} criados · {updated} atualizados · {inactivated} inativados",
     "import_processing": "Importação em andamento. Atualize a página em alguns instantes.",
-    "search_placeholder": "Buscar por Associados",
+    "search_placeholder": "Buscar por associados",
     "no_dependents": "Nenhum dependente cadastrado",
     "remove_photo": "Deseja remover sua foto de perfil?",
     "kinship": "Parentesco",
@@ -494,8 +508,7 @@
       "pt": "Português",
       "en": "English",
       "es": "Español"
-    },
-    "search_placeholder": "Buscar por associados"
+    }
   },
   "access_log": {
     "title": "Logs de Acesso",
@@ -572,149 +585,152 @@
     }
   },
   "loja": {
-    "product":                    "Produto",
-    "products":                   "Produtos",
-    "supplier_price":             "Preço Fornecedor",
-    "supplier":                   "Fornecedor",
-    "stock":                       "Estoque",
-    "interests":                  "Interessados",
-    "interested_btn":             "INTERESSADOS",
-    "interested_in":              "Interessados em",
-    "media":                      "Mídias",
-    "add_media":                  "Adicionar Mídia",
-    "uploading_media":            "Enviando mídia...",
-    "activate":                   "Ativar",
-    "deactivate":                 "Desativar",
-    "variation":                  "Variação",
-    "variation_tamanho":          "Tamanho",
-    "variation_cor":              "Cor",
-    "variation_modelo":           "Modelo",
-    "variation_label":            "Nome",
-    "variation_value":            "Valor (R$)",
-    "variation_stock":            "Estoque",
-    "variation_cor_placeholder":  "Ex: Roxo, Branco...",
+    "product": "Produto",
+    "products": "Produtos",
+    "supplier_price": "Preço Fornecedor",
+    "supplier": "Fornecedor",
+    "stock": "Estoque",
+    "interests": "Interessados",
+    "interested_btn": "INTERESSADOS",
+    "interested_in": "Interessados em",
+    "media": "Mídias",
+    "add_media": "Adicionar Mídia",
+    "uploading_media": "Enviando mídia...",
+    "activate": "Ativar",
+    "deactivate": "Desativar",
+    "variation": "Variação",
+    "variation_tamanho": "Tamanho",
+    "variation_cor": "Cor",
+    "variation_modelo": "Modelo",
+    "variation_label": "Nome",
+    "variation_value": "Valor (R$)",
+    "variation_stock": "Estoque",
+    "variation_cor_placeholder": "Ex: Roxo, Branco...",
     "variation_modelo_placeholder": "Ex: Associado, Premium...",
-    "variation_empty":            "Nenhuma variação adicionada",
-    "add_variation":              "Adicionar",
-    "filter_all":                 "Todos",
-    "filter_recent":              "Recentes",
-    "filter_others":              "Outros",
-    "btn_interested":             "Já tenho interesse",
-    "btn_want":                   "Eu quero"
+    "variation_empty": "Nenhuma variação adicionada",
+    "add_variation": "Adicionar",
+    "filter_all": "Todos",
+    "filter_recent": "Recentes",
+    "filter_others": "Outros",
+    "btn_interested": "Já tenho interesse",
+    "btn_want": "Eu quero",
+    "whatsapp_dialog_title": "Falar no WhatsApp",
+    "whatsapp_message": "Olá, eu sou o {nome} e tenho interesse nesse item da loja: {item}{variacao}.",
+    "whatsapp_btn_send": "Abrir WhatsApp"
   },
   "parceiro": {
-    "category":                "Categoria",
-    "company_name":            "Nome da Empresa",
-    "responsible":             "Responsável",
-    "discount_percentage":     "Desconto (%)",
-    "logo":                    "Logo",
-    "website":                 "Website",
-    "zip_code":                "CEP",
-    "address":                 "Endereço",
-    "neighborhood":            "Bairro",
-    "working_hours":           "Horário de Funcionamento",
+    "category": "Categoria",
+    "company_name": "Nome da Empresa",
+    "responsible": "Responsável",
+    "discount_percentage": "Desconto (%)",
+    "logo": "Logo",
+    "website": "Website",
+    "zip_code": "CEP",
+    "address": "Endereço",
+    "neighborhood": "Bairro",
+    "working_hours": "Horário de Funcionamento",
     "working_hours_placeholder": "Ex: Seg-Sex 08h-18h, Sáb 08h-12h",
-    "contract_start":          "Início do Contrato",
-    "contract_end":            "Fim do Contrato",
-    "contract_files":          "Arquivos do Contrato",
-    "add_file":                "Adicionar Arquivo",
-    "services":                "Serviços",
-    "service":                 "Serviço",
-    "service_category":        "Categoria do Serviço",
-    "service_number":          "Número do Serviço",
-    "price":                   "Preço",
-    "associate_price":         "Preço Associado",
-    "supplier_price":          "Preço Fornecedor",
-    "requires_scheduling":     "Requer Agendamento",
-    "search_placeholder":      "Pesquisar por serviço",
-    "import_parceiros":        "Parceiros",
-    "import_convenios":        "Convênios Médicos",
+    "contract_start": "Início do Contrato",
+    "contract_end": "Fim do Contrato",
+    "contract_files": "Arquivos do Contrato",
+    "add_file": "Adicionar Arquivo",
+    "services": "Serviços",
+    "service": "Serviço",
+    "service_category": "Categoria do Serviço",
+    "service_number": "Número do Serviço",
+    "price": "Preço",
+    "associate_price": "Preço Associado",
+    "supplier_price": "Preço Fornecedor",
+    "requires_scheduling": "Requer Agendamento",
+    "search_placeholder": "Pesquisar por serviço",
+    "import_parceiros": "Parceiros",
+    "import_convenios": "Convênios Médicos",
     "import_parceiros_result": "{created} criados · {updated} atualizados · {inactivated} inativados",
     "import_convenios_result": "{partners_created} clínicas criadas · {services_created} serviços criados · {partners_inactivated} inativados",
-    "import_processing":       "Importação em andamento. Atualize a página em alguns instantes.",
-    "cadastro_title":          "Cadastro de Parceiro",
-    "cadastro_parceiro":       "Cadastro de Parceiro",
-    "dados_parceiro":          "Dados de Parceiro",
-    "tab_dados":               "Dados da Empresa",
-    "tab_contato":             "Contato",
-    "tab_endereco":            "Endereço",
-    "tab_horario":             "Horário e Contrato",
-    "tab_servicos":            "Meus Serviços",
-    "usuario_parceiro":        "Usuário Parceiro",
-    "linked_user":             "Usuário Vinculado",
-    "home":                    "Início",
+    "import_processing": "Importação em andamento. Atualize a página em alguns instantes.",
+    "cadastro_title": "Cadastro de Parceiro",
+    "cadastro_parceiro": "Cadastro de Parceiro",
+    "dados_parceiro": "Dados de Parceiro",
+    "tab_dados": "Dados da Empresa",
+    "tab_contato": "Contato",
+    "tab_endereco": "Endereço",
+    "tab_horario": "Horário e Contrato",
+    "tab_servicos": "Meus Serviços",
+    "usuario_parceiro": "Usuário Parceiro",
+    "linked_user": "Usuário Vinculado",
+    "home": "Início",
     "dashboard": {
-      "title":         "Dashboard",
+      "title": "Dashboard",
       "authorization": "Autorizações Pendentes",
-      "scheduling":    "Agendamentos",
-      "completed":     "Concluídos",
-      "not_authorized":"Não Autorizados"
+      "scheduling": "Agendamentos",
+      "completed": "Concluídos",
+      "not_authorized": "Não Autorizados"
     }
   },
   "agendamento": {
-    "associado":                  "Associado",
-    "solicitar":                  "Solicitar",
-    "nova_solicitacao":           "Nova Solicitação",
-    "visao_geral":                "Visão Geral",
-    "aprovados_automaticamente":  "Aprovados Automaticamente",
-    "definir_data_hora":          "Definir data e horário",
-    "confirm_reject":             "Confirmar recusa deste agendamento?",
+    "associado": "Associado",
+    "solicitar": "Solicitar",
+    "nova_solicitacao": "Nova Solicitação",
+    "visao_geral": "Visão Geral",
+    "aprovados_automaticamente": "Aprovados Automaticamente",
+    "definir_data_hora": "Definir data e horário",
+    "confirm_reject": "Confirmar recusa deste agendamento?",
     "status": {
-      "pendente":   "Pendente",
+      "pendente": "Pendente",
       "confirmado": "Confirmado",
-      "recusado":   "Recusado",
-      "cancelado":  "Cancelado",
-      "concluido":  "Concluído"
+      "recusado": "Recusado",
+      "cancelado": "Cancelado",
+      "concluido": "Concluído"
     },
     "col": {
-      "pedido":     "Pedido",
-      "parceiro":   "Parceiro",
-      "servico":    "Serviço",
-      "solicitacao":"Solicitação"
+      "pedido": "Pedido",
+      "parceiro": "Parceiro",
+      "servico": "Serviço",
+      "solicitacao": "Solicitação"
     }
   },
   "notification": {
-    "empty":                "Nenhuma notificação no momento",
-    "new":                  "Nova",
-    "history":              "Histórico",
-    "title_label":          "Título",
-    "title_placeholder":    "Título da notificação",
-    "message_label":        "Mensagem",
-    "message_placeholder":  "Mensagem da notificação",
-    "recipients":           "Destinatários",
-    "by_position":          "Por Cargo",
-    "by_sector":            "Por Setor",
-    "media":                "Mídia",
-    "send":                 "Enviar",
-    "all":                  "Todos",
-    "recipient_associado":  "Associados",
-    "recipient_parceiro":   "Parceiros",
-    "details":              "Detalhes",
-    "sent_to":              "Enviado para {count} usuário(s)",
-    "seen_by":              "Visto por {count} usuário(s)",
-    "pending_read_title":   "Notificações Pendentes",
+    "empty": "Nenhuma notificação no momento",
+    "new": "Nova",
+    "history": "Histórico",
+    "title_label": "Título",
+    "title_placeholder": "Título da notificação",
+    "message_label": "Mensagem",
+    "message_placeholder": "Mensagem da notificação",
+    "recipients": "Destinatários",
+    "by_position": "Por Cargo",
+    "by_sector": "Por Setor",
+    "media": "Mídia",
+    "send": "Enviar",
+    "all": "Todos",
+    "recipient_associado": "Associados",
+    "recipient_parceiro": "Parceiros",
+    "details": "Detalhes",
+    "sent_to": "Enviado para {count} usuário(s)",
+    "seen_by": "Visto por {count} usuário(s)",
+    "pending_read_title": "Notificações Pendentes",
     "pending_read_subtitle": "Você possui notificações não lidas. Leia todas para continuar.",
-    "pending_read_hint":    "Clique em cada notificação para marcá-la como lida.",
-    "pending_read_close":   "Fechar"
+    "pending_read_hint": "Clique em cada notificação para marcá-la como lida.",
+    "pending_read_close": "Fechar"
   },
   "associate_validation": {
-    "title":               "Validar Carteirinha",
-    "qr_code":             "QR Code",
-    "description":         "Busque o associado pelo crachá ou CPF",
-    "search_placeholder":  "Crachá ou CPF",
-    "search":              "Buscar",
-    "associate_found":     "Associado Encontrado",
-    "name":                "Nome",
-    "cpf":                 "CPF",
-    "registration":        "Matrícula",
-    "expiry_date":         "Validade",
-    "no_photo":            "Sem foto"
+    "title": "Validar Carteirinha",
+    "qr_code": "QR Code",
+    "description": "Busque o associado pelo crachá ou CPF",
+    "search_placeholder": "Crachá ou CPF",
+    "search": "Buscar",
+    "associate_found": "Associado Encontrado",
+    "name": "Nome",
+    "cpf": "CPF",
+    "registration": "Matrícula",
+    "expiry_date": "Validade",
+    "no_photo": "Sem foto"
   },
   "relatorio": {
-    "exportar_excel":    "Exportar Excel",
-    "novos_associados":  "Novos Associados",
-    "contatos":          "Contatos",
-    "exclusoes_mes":     "Exclusões do Mês",
+    "exportar_excel": "Exportar Excel",
+    "novos_associados": "Novos Associados",
+    "contatos": "Contatos",
+    "exclusoes_mes": "Exclusões do Mês",
     "col": {
       "cadastro": "Cadastro",
       "exclusao": "Exclusão"
@@ -722,12 +738,12 @@
   },
   "import_log": {
     "history_title": "Histórico de Importações",
-    "date_time":     "Data/Hora",
-    "imported_by":   "Importado por",
-    "total":         "Total",
-    "created":       "Novos",
-    "updated":       "Atualizados",
-    "inactivated":   "Desativados",
-    "no_history":    "Nenhuma importação registrada"
+    "date_time": "Data/Hora",
+    "imported_by": "Importado por",
+    "total": "Total",
+    "created": "Novos",
+    "updated": "Atualizados",
+    "inactivated": "Desativados",
+    "no_history": "Nenhuma importação registrada"
   }
 }

+ 30 - 19
src/pages/associado/loja/AssociadoLojaPage.vue

@@ -4,7 +4,6 @@
 
     <div class="q-pa-md">
 
-      <!-- Search -->
       <div class="row q-col-gutter-sm q-mb-md">
         <div class="col-12 col-md-5">
           <q-input
@@ -21,7 +20,6 @@
         </div>
       </div>
 
-      <!-- Category chips -->
       <div class="row q-gutter-xs q-mb-md flex-wrap">
         <div
           :class="['cat-chip', activeTab === 'all' ? 'cat-chip--selected' : 'cat-chip--default']"
@@ -48,17 +46,14 @@
         </div>
       </div>
 
-      <!-- Loading -->
       <div v-if="loading" class="flex flex-center q-py-xl">
         <q-spinner color="primary" size="48px" />
       </div>
 
-      <!-- Empty -->
       <div v-else-if="pagedItems.length === 0" class="text-center text-grey q-py-xl">
         {{ $t('http.errors.no_records_found') }}
       </div>
 
-      <!-- Grid -->
       <div v-else class="row q-col-gutter-md items-stretch">
         <div
           v-for="item in pagedItems"
@@ -69,10 +64,8 @@
             <q-card-section class="q-pa-sm col column" style="height: 100%">
               <div class="row no-wrap store-card-inner" style="flex: 1">
 
-                <!-- LEFT -->
                 <div class="col column justify-between q-pr-sm">
                   <div>
-                    <!-- Category badge -->
                     <div class="q-mb-xs">
                       <span v-if="item.category?.name" class="badge-category">
                         {{ item.category.name }}
@@ -87,7 +80,6 @@
                       {{ item.description }}
                     </div>
 
-                    <!-- Variations -->
                     <template v-if="item.variations?.length">
                       <div class="text-caption text-grey-6 q-mb-xs">
                         {{ variationTypeLabel(item) }}
@@ -110,7 +102,6 @@
                     </template>
                   </div>
 
-                  <!-- Price -->
                   <div class="column items-start q-mt-sm">
                     <span v-if="item.price" class="text-caption text-grey-5 text-strike">
                       R$ {{ formatPrice(item.price) }}
@@ -121,7 +112,6 @@
                   </div>
                 </div>
 
-                <!-- RIGHT -->
                 <div class="store-card-right column items-stretch no-wrap">
                   <div class="store-card-image col">
                     <img
@@ -139,7 +129,6 @@
                     />
                   </div>
 
-                  <!-- Button -->
                   <q-btn
                     unelevated
                     size="sm"
@@ -151,6 +140,15 @@
                     padding="5px 8px"
                     @click="toggleInterest(item)"
                   />
+                  <q-btn
+                    unelevated
+                    size="sm"
+                    class="q-mt-xs btn-whatsapp"
+                    icon="mdi-whatsapp"
+                    style="width: 100%"
+                    padding="5px 8px"
+                    @click="openWhatsAppDialog(item)"
+                  />
                 </div>
 
               </div>
@@ -159,7 +157,6 @@
         </div>
       </div>
 
-      <!-- Pagination -->
       <div v-if="totalPages > 1" class="flex flex-center q-mt-lg">
         <q-pagination
           v-model="currentPage"
@@ -181,6 +178,7 @@ import { normalizeString } from "src/helpers/utils";
 import { getStoreItemsAssociado, toggleInterestAssociado as apiToggleInterest } from "src/api/storeItem";
 import { getCategories } from "src/api/category";
 import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
+import WhatsAppLojaDialog from "./components/WhatsAppLojaDialog.vue";
 
 const $q = useQuasar();
 const { t } = useI18n();
@@ -253,17 +251,22 @@ const toggleInterest = async (item) => {
     const result = await apiToggleInterest(item.id);
     item.user_interested = result.interested;
     item.interests_count = (item.interests_count ?? 0) + (result.interested ? 1 : -1);
-    $q.notify({
-      type: "positive",
-      message: result.interested
-        ? t("loja.btn_interested")
-        : t("http.success"),
-    });
   } catch {
-    $q.notify({ type: "negative", message: t("http.errors.failed") });
+    // silent
   }
 };
 
+const openWhatsAppDialog = (item) => {
+  const variation = activeVariation(item);
+  $q.dialog({
+    component: WhatsAppLojaDialog,
+    componentProps: {
+      item,
+      variationLabel: variation?.variation_label ?? null,
+    },
+  });
+};
+
 onMounted(async () => {
   try {
     const [itemsData, catsData] = await Promise.all([
@@ -401,6 +404,14 @@ onMounted(async () => {
 
 .btn-interested :deep(.q-icon) { color: white !important; }
 
+.btn-whatsapp {
+  background: #25d366 !important;
+  color: white !important;
+  border-radius: 8px !important;
+}
+
+.btn-whatsapp :deep(.q-icon) { color: white !important; }
+
 // --- text colors ---
 .text-violet-dark   { color: #4d1658; }
 .text-violet-medium { color: #7b2d97; }

+ 83 - 0
src/pages/associado/loja/components/WhatsAppLojaDialog.vue

@@ -0,0 +1,83 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card class="q-dialog-plugin overflow-hidden" style="min-width: 300px; max-width: 460px; width: 92vw">
+      <DefaultDialogHeader :title="() => $t('loja.whatsapp_dialog_title')" @close="onDialogCancel" />
+
+      <q-card-section class="q-pt-sm">
+        <div class="wpp-message-box">
+          <q-icon name="mdi-whatsapp" color="positive" size="22px" class="wpp-icon" />
+          <p class="text-body2 q-mb-none wpp-text">{{ message }}</p>
+        </div>
+      </q-card-section>
+
+      <q-card-actions align="right" class="q-px-md q-pb-md">
+        <q-btn
+          flat
+          color="grey-7"
+          :label="$t('common.actions.cancel')"
+          @click="onDialogCancel"
+        />
+        <q-btn
+          unelevated
+          color="positive"
+          icon="mdi-whatsapp"
+          :label="$t('loja.whatsapp_btn_send')"
+          @click="openWhatsApp"
+        />
+      </q-card-actions>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { computed } from "vue";
+import { useDialogPluginComponent } from "quasar";
+import { useI18n } from "vue-i18n";
+import { userStore } from "src/stores/user";
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const { item, variationLabel } = defineProps({
+  item: { type: Object, required: true },
+  variationLabel: { type: String, default: null },
+});
+
+const { t } = useI18n();
+const { dialogRef, onDialogHide, onDialogCancel } = useDialogPluginComponent();
+const store = userStore();
+
+const message = computed(() => {
+  const nome = store.user?.name ?? "";
+  const variacao = variationLabel ? ` - ${variationLabel}` : "";
+  return t("loja.whatsapp_message", { nome, item: item.name, variacao });
+});
+
+const openWhatsApp = () => {
+  const encoded = encodeURIComponent(message.value);
+  window.open(`https://wa.me/5545991266531?text=${encoded}`, "_blank");
+  onDialogCancel();
+};
+</script>
+
+<style scoped lang="scss">
+.wpp-message-box {
+  display: flex;
+  align-items: flex-start;
+  gap: 10px;
+  background: #f0fdf4;
+  border: 1px solid #86efac;
+  border-radius: 10px;
+  padding: 14px;
+}
+
+.wpp-icon {
+  flex-shrink: 0;
+  margin-top: 1px;
+}
+
+.wpp-text {
+  line-height: 1.55;
+  color: #166534;
+}
+</style>