mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-16 19:48:48 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eaa7771dec |
+14
-12
@@ -106,18 +106,20 @@ export const ResponseCardModal = ({
|
||||
</DialogDescription>
|
||||
</VisuallyHidden>
|
||||
<DialogBody>
|
||||
<SingleResponseCard
|
||||
survey={survey}
|
||||
response={responses[currentIndex]}
|
||||
user={user}
|
||||
environment={environment}
|
||||
environmentTags={environmentTags}
|
||||
isReadOnly={isReadOnly}
|
||||
updateResponse={updateResponse}
|
||||
updateResponseList={updateResponseList}
|
||||
setSelectedResponseId={setSelectedResponseId}
|
||||
locale={locale}
|
||||
/>
|
||||
<div className="my-3">
|
||||
<SingleResponseCard
|
||||
survey={survey}
|
||||
response={responses[currentIndex]}
|
||||
user={user}
|
||||
environment={environment}
|
||||
environmentTags={environmentTags}
|
||||
isReadOnly={isReadOnly}
|
||||
updateResponse={updateResponse}
|
||||
updateResponseList={updateResponseList}
|
||||
setSelectedResponseId={setSelectedResponseId}
|
||||
locale={locale}
|
||||
/>
|
||||
</div>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
|
||||
+7
-2
@@ -11,6 +11,7 @@ import { renderHyperlinkedContent } from "@/modules/analysis/utils";
|
||||
import { PersonAvatar } from "@/modules/ui/components/avatars";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { EmptyState } from "@/modules/ui/components/empty-state";
|
||||
import { IdBadge } from "@/modules/ui/components/id-badge";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/modules/ui/components/table";
|
||||
import { ElementSummaryHeader } from "./ElementSummaryHeader";
|
||||
|
||||
@@ -47,7 +48,8 @@ export const OpenTextSummary = ({ elementSummary, environmentId, survey, locale
|
||||
<TableRow>
|
||||
<TableHead className="w-1/4">{t("common.user")}</TableHead>
|
||||
<TableHead className="w-2/4">{t("common.response")}</TableHead>
|
||||
<TableHead className="w-1/4">{t("common.time")}</TableHead>
|
||||
<TableHead className="w-1/6">{t("common.time")}</TableHead>
|
||||
<TableHead className="w-1/6">{t("common.response_id")}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -79,9 +81,12 @@ export const OpenTextSummary = ({ elementSummary, environmentId, survey, locale
|
||||
? renderHyperlinkedContent(response.value)
|
||||
: response.value}
|
||||
</TableCell>
|
||||
<TableCell className="w-1/4">
|
||||
<TableCell className="w-1/6">
|
||||
{timeSince(new Date(response.updatedAt).toISOString(), locale)}
|
||||
</TableCell>
|
||||
<TableCell className="w-1/6">
|
||||
<IdBadge id={response.id} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
||||
+9
-3
@@ -214,6 +214,9 @@ checksums:
|
||||
common/failed_to_load_organizations: 512808a2b674c7c28bca73f8f91fd87e
|
||||
common/failed_to_load_workspaces: 6ee3448097394517dc605074cd4e6ea4
|
||||
common/field_placeholder: ec26d96643d86da164162204ec6c650f
|
||||
common/file_size_must_be_less_than_5_mb: a7d8ef9f888bfb3de2b589947fa2a63f
|
||||
common/file_storage_not_set_up: ed82fc9c54da2f16245eaea9f8aa08f3
|
||||
common/file_upload_service_unavailable: 93a6a904cef89cc18d2c4a65e2d581cc
|
||||
common/filter: 626325a05e4c8800f7ede7012b0cadaf
|
||||
common/finish: ffa7a10f71182b48fefed7135bee24fa
|
||||
common/first_name: cf040a5d6a9fd696be400380cc99f54b
|
||||
@@ -432,7 +435,6 @@ checksums:
|
||||
common/trial_one_day_remaining: 2d64d39fca9589c4865357817bcc24d5
|
||||
common/try_again: 33dd8820e743e35a66e6977f69e9d3b5
|
||||
common/type: f04471a7ddac844b9ad145eb9911ef75
|
||||
common/unknown_survey: dd8f6985e17ccf19fac1776e18b2c498
|
||||
common/unlock_more_workspaces_with_a_higher_plan: fe1590075b855bb4306c9388b65143b0
|
||||
common/update: 079fc039262fd31b10532929685c2d1b
|
||||
common/updated: 8aa8ff2dc2977ca4b269e80a513100b4
|
||||
@@ -677,6 +679,7 @@ checksums:
|
||||
environments/contacts/select_a_survey: 1f49086dfb874307aae1136e88c3d514
|
||||
environments/contacts/select_attribute: d93fb60eb4fbb42bf13a22f6216fbd79
|
||||
environments/contacts/select_attribute_key: 673a6683fab41b387d921841cded7e38
|
||||
environments/contacts/survey_response_created: e4a6eaac2acd8defca3ff57eae045ba6
|
||||
environments/contacts/survey_viewed: 646d413218626787b0373ffd71cb7451
|
||||
environments/contacts/survey_viewed_at: 2ab535237af5c3c3f33acc792a7e70a4
|
||||
environments/contacts/system_attributes: eadb6a8888c7b32c0e68881f945ae9b6
|
||||
@@ -1809,6 +1812,7 @@ checksums:
|
||||
environments/surveys/responses/completed: 2dca9d2e4c0fe669801112a66d679f6d
|
||||
environments/surveys/responses/country: 73581fc33a1e83e6a56db73558e7b5c6
|
||||
environments/surveys/responses/decrement_quotas: 9ef63d3e9214c508eb040eb41c25a5c4
|
||||
environments/surveys/responses/delete_response: d86cb6fe4af953cde58f12092962bca4
|
||||
environments/surveys/responses/delete_response_confirmation: 83a43954ca60c8ef30b9683253a6f5ea
|
||||
environments/surveys/responses/delete_response_quotas: 6719c90d8019000ca0a74586fb3b6a65
|
||||
environments/surveys/responses/device: c009f849d689c745de9e38ad17644c7a
|
||||
@@ -1833,8 +1837,10 @@ checksums:
|
||||
environments/surveys/responses/this_response_is_in_progress: 7d785fcb597ea30466467084fd474904
|
||||
environments/surveys/responses/zip_post_code: ab7dc45bd5f9e37930586e2db17e4304
|
||||
environments/surveys/search_by_survey_name: 44cf2e6f8ba43d233fb33939431eba99
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_description: 53c6d2b6cf597115b1f5a280ce7e9cab
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_title: 9d708fe4ced64ddedd307fb61827cd03
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_description: 994c76257cc373388a3870caf9d85dc7
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_placeholder: e089b0f1838164b2ef2f74076477d8f2
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_required: 36f60e76ebed5af11661ac7bbadd9a2b
|
||||
environments/surveys/share/anonymous_links/custom_single_use_id_title: 0a1b97ed6fd82d9b0f9f43750d45fbe3
|
||||
environments/surveys/share/anonymous_links/custom_start_point: 4ea6552b37339d17e02f3bce8c7e4125
|
||||
environments/surveys/share/anonymous_links/data_prefilling: 82f0e31e90f1f2ca31361df9893e117c
|
||||
environments/surveys/share/anonymous_links/description: d13534a22f135420651ebfd218a4f01b
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "Noch 1 Tag in deiner Testphase",
|
||||
"try_again": "Versuch's nochmal",
|
||||
"type": "Typ",
|
||||
"unknown_survey": "Unbekannte Umfrage",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Schalten Sie mehr Projekte mit einem höheren Tarif frei.",
|
||||
"update": "Aktualisierung",
|
||||
"updated": "Aktualisiert",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Wähle eine Umfrage aus",
|
||||
"select_attribute": "Attribut auswählen",
|
||||
"select_attribute_key": "Attributschlüssel auswählen",
|
||||
"survey_response_created": "Antwort erstellt",
|
||||
"survey_viewed": "Umfrage angesehen",
|
||||
"survey_viewed_at": "Angesehen am",
|
||||
"system_attributes": "Systemattribute",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Erledigt ✅",
|
||||
"country": "Land",
|
||||
"decrement_quotas": "Alle Grenzwerte der Kontingente einschließlich dieser Antwort verringern",
|
||||
"delete_response": "Antwort löschen",
|
||||
"delete_response_confirmation": "Dies wird die Umfrageantwort einschließlich aller Antworten, Tags, angehängter Dokumente und Antwort-Metadaten löschen.",
|
||||
"delete_response_quotas": "Die Antwort ist Teil der Quoten für diese Umfrage. Wie möchten Sie die Quoten verwalten?",
|
||||
"device": "Gerät",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Nach Umfragenamen suchen",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Erstelle eine lesbare Einmal-ID und kopiere einen signierten Link dafür.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Verwende eine benutzerdefinierte Einmal-ID in der URL.",
|
||||
"custom_start_point": "Benutzerdefinierter Startpunkt",
|
||||
"data_prefilling": "Daten-Prefilling",
|
||||
"description": "Antworten, die von diesen Links kommen, werden anonym",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 day left in your trial",
|
||||
"try_again": "Try again",
|
||||
"type": "Type",
|
||||
"unknown_survey": "Unknown survey",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Unlock more workspaces with a higher plan.",
|
||||
"update": "Update",
|
||||
"updated": "Updated",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Select a survey",
|
||||
"select_attribute": "Select Attribute",
|
||||
"select_attribute_key": "Select attribute key",
|
||||
"survey_response_created": "Response created",
|
||||
"survey_viewed": "Survey viewed",
|
||||
"survey_viewed_at": "Viewed At",
|
||||
"system_attributes": "System Attributes",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Completed ✅",
|
||||
"country": "Country",
|
||||
"decrement_quotas": "Decrement all limits of quotas including this response",
|
||||
"delete_response": "Delete response",
|
||||
"delete_response_confirmation": "This will delete the survey response, including all answers, tags, attached documents, and response metadata.",
|
||||
"delete_response_quotas": "The response is part of quotas for this survey. How do you want to handle the quotas?",
|
||||
"device": "Device",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 día restante en tu prueba",
|
||||
"try_again": "Intentar de nuevo",
|
||||
"type": "Tipo",
|
||||
"unknown_survey": "Encuesta desconocida",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Desbloquea más proyectos con un plan superior.",
|
||||
"update": "Actualizar",
|
||||
"updated": "Actualizado",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Selecciona una encuesta",
|
||||
"select_attribute": "Seleccionar atributo",
|
||||
"select_attribute_key": "Seleccionar clave de atributo",
|
||||
"survey_response_created": "Respuesta creada",
|
||||
"survey_viewed": "Encuesta vista",
|
||||
"survey_viewed_at": "Vista el",
|
||||
"system_attributes": "Atributos del sistema",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Completado ✅",
|
||||
"country": "País",
|
||||
"decrement_quotas": "Reducir todos los límites de cuotas que incluyen esta respuesta",
|
||||
"delete_response": "Eliminar respuesta",
|
||||
"delete_response_confirmation": "Esto eliminará la respuesta de la encuesta, incluyendo todas las respuestas, etiquetas, documentos adjuntos y metadatos de respuesta.",
|
||||
"delete_response_quotas": "La respuesta forma parte de cuotas para esta encuesta. ¿Cómo quieres gestionar las cuotas?",
|
||||
"device": "Dispositivo",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Buscar por nombre de encuesta",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Crea un ID legible de un solo uso y copia un enlace firmado para él.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Usa un ID personalizado de un solo uso en la URL.",
|
||||
"custom_start_point": "Punto de inicio personalizado",
|
||||
"data_prefilling": "Prellenado de datos",
|
||||
"description": "Las respuestas procedentes de estos enlaces serán anónimas",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 jour restant dans votre période d'essai",
|
||||
"try_again": "Réessayer",
|
||||
"type": "Type",
|
||||
"unknown_survey": "Enquête inconnue",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Débloquez plus de projets avec un forfait supérieur.",
|
||||
"update": "Mise à jour",
|
||||
"updated": "Mise à jour",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Sélectionner une enquête",
|
||||
"select_attribute": "Sélectionner un attribut",
|
||||
"select_attribute_key": "Sélectionner une clé d'attribut",
|
||||
"survey_response_created": "Réponse créée",
|
||||
"survey_viewed": "Enquête consultée",
|
||||
"survey_viewed_at": "Consultée le",
|
||||
"system_attributes": "Attributs système",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Terminé ✅",
|
||||
"country": "Pays",
|
||||
"decrement_quotas": "Décrémentez toutes les limites des quotas y compris cette réponse",
|
||||
"delete_response": "Supprimer la réponse",
|
||||
"delete_response_confirmation": "Cela supprimera la réponse au sondage, y compris toutes les réponses, les étiquettes, les documents joints et les métadonnées de réponse.",
|
||||
"delete_response_quotas": "La réponse fait partie des quotas pour ce sondage. Comment voulez-vous gérer les quotas ?",
|
||||
"device": "Dispositif",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Recherche par nom d'enquête",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Créez un identifiant à usage unique lisible et copiez un lien signé pour celui-ci.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Utilisez un identifiant personnalisé à usage unique dans l'URL.",
|
||||
"custom_start_point": "Point de départ personnalisé",
|
||||
"data_prefilling": "Préremplissage des données",
|
||||
"description": "Les réponses provenant de ces liens seront anonymes",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 nap van hátra a próbaidőszakából",
|
||||
"try_again": "Próbálja újra",
|
||||
"type": "Típus",
|
||||
"unknown_survey": "Ismeretlen kérdőív",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Több munkaterület feloldása egy magasabb csomaggal.",
|
||||
"update": "Frissítés",
|
||||
"updated": "Frissítve",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Kérdőív kiválasztása",
|
||||
"select_attribute": "Attribútum kiválasztása",
|
||||
"select_attribute_key": "Attribútum kulcsának kiválasztása",
|
||||
"survey_response_created": "Válasz létrehozva",
|
||||
"survey_viewed": "Kérdőív megtekintve",
|
||||
"survey_viewed_at": "Megtekintve ekkor:",
|
||||
"system_attributes": "Rendszerattribútumok",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Befejezve ✅",
|
||||
"country": "Ország",
|
||||
"decrement_quotas": "A kvóták összes korlátjának csökkentése, beleértve ezt a választ is",
|
||||
"delete_response": "Válasz törlése",
|
||||
"delete_response_confirmation": "Ez törölni fogja a kérdőívre adott választ, beleértve az összes választ, címkét, csatolt dokumentumot és a válasz metaadatait.",
|
||||
"delete_response_quotas": "A válasz a kérdőív kvótáinak részét képezik. Hogyan szeretné kezelni a kvótákat?",
|
||||
"device": "Eszköz",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Keresés kérdőívnév alapján",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Hozzon létre egy olvasható, egyszer használatos azonosítót, és másoljon ki egy aláírt linket hozzá.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Használjon egyedi, egyszer használatos azonosítót az URL-ben.",
|
||||
"custom_start_point": "Egyéni kezdési pont",
|
||||
"data_prefilling": "Adatok előre kitöltése",
|
||||
"description": "Az ezekről a hivatkozásokról érkező válaszok névtelenek lesznek",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "トライアル期間の残り1日",
|
||||
"try_again": "もう一度お試しください",
|
||||
"type": "種類",
|
||||
"unknown_survey": "不明なフォーム",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "上位プランでより多くのワークスペースを利用できます。",
|
||||
"update": "更新",
|
||||
"updated": "更新済み",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "フォームを選択",
|
||||
"select_attribute": "属性を選択",
|
||||
"select_attribute_key": "属性キーを選択",
|
||||
"survey_response_created": "回答が作成されました",
|
||||
"survey_viewed": "フォームを閲覧",
|
||||
"survey_viewed_at": "閲覧日時",
|
||||
"system_attributes": "システム属性",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "完了 ✅",
|
||||
"country": "国",
|
||||
"decrement_quotas": "すべて の 制限 を 減少 し、 この 回答 を 含む しきい値",
|
||||
"delete_response": "回答を削除",
|
||||
"delete_response_confirmation": "これにより、すべての回答、タグ、添付されたドキュメント、および回答メタデータを含むフォームの回答が削除されます。",
|
||||
"delete_response_quotas": "この回答は、このアンケートの割り当ての一部です。 割り当てをどのように処理しますか?",
|
||||
"device": "デバイス",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "フォーム名で検索",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "読みやすいワンタイムIDを作成し、それに対応する署名付きリンクをコピーします。",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "URLにカスタムワンタイムIDを使用する。",
|
||||
"custom_start_point": "カスタム開始点",
|
||||
"data_prefilling": "データの事前入力",
|
||||
"description": "これらのリンクからの回答は匿名になります",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 dag over in je proefperiode",
|
||||
"try_again": "Probeer het opnieuw",
|
||||
"type": "Type",
|
||||
"unknown_survey": "Onbekende enquête",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Ontgrendel meer werkruimtes met een hoger abonnement.",
|
||||
"update": "Update",
|
||||
"updated": "Bijgewerkt",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Selecteer een enquête",
|
||||
"select_attribute": "Selecteer Kenmerk",
|
||||
"select_attribute_key": "Selecteer kenmerksleutel",
|
||||
"survey_response_created": "Antwoord aangemaakt",
|
||||
"survey_viewed": "Enquête bekeken",
|
||||
"survey_viewed_at": "Bekeken op",
|
||||
"system_attributes": "Systeemkenmerken",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Voltooid ✅",
|
||||
"country": "Land",
|
||||
"decrement_quotas": "Verlaag alle limieten van quota, inclusief dit antwoord",
|
||||
"delete_response": "Antwoord verwijderen",
|
||||
"delete_response_confirmation": "Hierdoor wordt het enquêteantwoord verwijderd, inclusief alle antwoorden, tags, bijgevoegde documenten en metagegevens van het antwoord.",
|
||||
"delete_response_quotas": "De respons maakt deel uit van de quota voor dit onderzoek. Hoe wilt u omgaan met de quota?",
|
||||
"device": "Apparaat",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Zoek op enquêtenaam",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Maak een leesbare eenmalige ID aan en kopieer een ondertekende link hiervoor.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Gebruik een aangepaste eenmalige ID in de URL.",
|
||||
"custom_start_point": "Aangepast startpunt",
|
||||
"data_prefilling": "Gegevens vooraf invullen",
|
||||
"description": "Reacties afkomstig van deze links zijn anoniem",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 dia restante no seu período de teste",
|
||||
"try_again": "Tenta de novo",
|
||||
"type": "Tipo",
|
||||
"unknown_survey": "Pesquisa desconhecida",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Desbloqueie mais projetos com um plano superior.",
|
||||
"update": "atualizar",
|
||||
"updated": "atualizado",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Selecione uma pesquisa",
|
||||
"select_attribute": "Selecionar Atributo",
|
||||
"select_attribute_key": "Selecionar chave de atributo",
|
||||
"survey_response_created": "Resposta criada",
|
||||
"survey_viewed": "Pesquisa visualizada",
|
||||
"survey_viewed_at": "Visualizada em",
|
||||
"system_attributes": "Atributos do sistema",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Concluído ✅",
|
||||
"country": "País",
|
||||
"decrement_quotas": "Diminua todos os limites de cotas, incluindo esta resposta",
|
||||
"delete_response": "Excluir resposta",
|
||||
"delete_response_confirmation": "Isso irá excluir a resposta da pesquisa, incluindo todas as respostas, etiquetas, documentos anexados e metadados da resposta.",
|
||||
"delete_response_quotas": "A resposta faz parte das cotas desta pesquisa. Como você quer gerenciar as cotas?",
|
||||
"device": "dispositivo",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Buscar pelo nome da pesquisa",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Crie um ID de uso único legível e copie um link assinado para ele.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Use um ID de uso único personalizado na URL.",
|
||||
"custom_start_point": "Ponto de início personalizado",
|
||||
"data_prefilling": "preenchimento automático de dados",
|
||||
"description": "Respostas vindas desses links serão anônimas",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 dia restante no teu período de teste",
|
||||
"try_again": "Tente novamente",
|
||||
"type": "Tipo",
|
||||
"unknown_survey": "Inquérito desconhecido",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Desbloqueie mais projetos com um plano superior.",
|
||||
"update": "Atualizar",
|
||||
"updated": "Atualizado",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Selecione um inquérito",
|
||||
"select_attribute": "Selecionar Atributo",
|
||||
"select_attribute_key": "Selecionar chave de atributo",
|
||||
"survey_response_created": "Resposta criada",
|
||||
"survey_viewed": "Inquérito visualizado",
|
||||
"survey_viewed_at": "Visualizado em",
|
||||
"system_attributes": "Atributos do sistema",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Concluído ✅",
|
||||
"country": "País",
|
||||
"decrement_quotas": "Decrementar todos os limites das cotas incluindo esta resposta",
|
||||
"delete_response": "Eliminar resposta",
|
||||
"delete_response_confirmation": "Isto irá apagar a resposta do inquérito, incluindo todas as respostas, etiquetas, documentos anexos e metadados da resposta.",
|
||||
"delete_response_quotas": "A resposta faz parte das quotas deste inquérito. Como deseja gerir as quotas?",
|
||||
"device": "Dispositivo",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Pesquisar por nome do inquérito",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Cria um ID de utilização única legível e copia uma ligação assinada para o mesmo.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Usa um ID de utilização única personalizado no URL.",
|
||||
"custom_start_point": "Ponto de início personalizado",
|
||||
"data_prefilling": "Pré-preenchimento de dados",
|
||||
"description": "Respostas provenientes destes links serão anónimas",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 zi rămasă în perioada ta de probă",
|
||||
"try_again": "Încearcă din nou",
|
||||
"type": "Tip",
|
||||
"unknown_survey": "Chestionar necunoscut",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Deblochează mai multe workspaces cu un plan superior.",
|
||||
"update": "Actualizare",
|
||||
"updated": "Actualizat",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Selectați un sondaj",
|
||||
"select_attribute": "Selectează atributul",
|
||||
"select_attribute_key": "Selectează cheia atributului",
|
||||
"survey_response_created": "Răspuns creat",
|
||||
"survey_viewed": "Chestionar vizualizat",
|
||||
"survey_viewed_at": "Vizualizat la",
|
||||
"system_attributes": "Atribute de sistem",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Finalizat ✅",
|
||||
"country": "Țară",
|
||||
"decrement_quotas": "Decrementați toate limitele cotelor, inclusiv acest răspuns",
|
||||
"delete_response": "Șterge răspunsul",
|
||||
"delete_response_confirmation": "Aceasta va șterge răspunsul la sondaj, inclusiv toate răspunsurile, etichetele, documentele atașate și metadatele răspunsului.",
|
||||
"delete_response_quotas": "Răspunsul face parte din cotele pentru acest sondaj. Cum doriți să gestionați cotele?",
|
||||
"device": "Dispozitiv",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Căutare după nume chestionar",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Creează un ID de unică folosință lizibil și copiază un link semnat pentru acesta.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Folosește un ID personalizat de unică folosință în URL.",
|
||||
"custom_start_point": "Punct de start personalizat",
|
||||
"data_prefilling": "Precompletare date",
|
||||
"description": "Răspunsurile provenite de la aceste linkuri vor fi anonime",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "Остался 1 день пробного периода",
|
||||
"try_again": "Попробуйте ещё раз",
|
||||
"type": "Тип",
|
||||
"unknown_survey": "Неизвестный опрос",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Откройте больше рабочих пространств с более высоким тарифом.",
|
||||
"update": "Обновить",
|
||||
"updated": "Обновлено",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Выберите опрос",
|
||||
"select_attribute": "Выберите атрибут",
|
||||
"select_attribute_key": "Выберите ключ атрибута",
|
||||
"survey_response_created": "Ответ создан",
|
||||
"survey_viewed": "Опрос просмотрен",
|
||||
"survey_viewed_at": "Просмотрено",
|
||||
"system_attributes": "Системные атрибуты",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Завершено ✅",
|
||||
"country": "Страна",
|
||||
"decrement_quotas": "Уменьшить все лимиты квот, включая этот ответ",
|
||||
"delete_response": "Удалить ответ",
|
||||
"delete_response_confirmation": "Это действие удалит ответ на опрос, включая все ответы, теги, вложенные документы и метаданные ответа.",
|
||||
"delete_response_quotas": "Ответ входит в квоты для этого опроса. Как вы хотите обработать квоты?",
|
||||
"device": "Устройство",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Поиск по названию опроса",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Создайте читаемый одноразовый ID и скопируйте подписанную ссылку для него.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Используй собственный одноразовый ID в URL.",
|
||||
"custom_start_point": "Пользовательская точка старта",
|
||||
"data_prefilling": "Предзаполнение данных",
|
||||
"description": "Ответы, полученные по этим ссылкам, будут анонимными",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "1 dag kvar av din provperiod",
|
||||
"try_again": "Försök igen",
|
||||
"type": "Typ",
|
||||
"unknown_survey": "Okänd enkät",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Lås upp fler arbetsytor med ett högre abonnemang.",
|
||||
"update": "Uppdatera",
|
||||
"updated": "Uppdaterad",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Välj en enkät",
|
||||
"select_attribute": "Välj attribut",
|
||||
"select_attribute_key": "Välj attributnyckel",
|
||||
"survey_response_created": "Svar skapat",
|
||||
"survey_viewed": "Enkät visad",
|
||||
"survey_viewed_at": "Visad kl.",
|
||||
"system_attributes": "Systemattribut",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Slutförd ✅",
|
||||
"country": "Land",
|
||||
"decrement_quotas": "Minska alla gränser för kvoter inklusive detta svar",
|
||||
"delete_response": "Ta bort svar",
|
||||
"delete_response_confirmation": "Detta kommer att ta bort enkätsvaret, inklusive alla svar, taggar, bifogade dokument och svarsmetadata.",
|
||||
"delete_response_quotas": "Svaret är del av kvoter för denna enkät. Hur vill du hantera kvoterna?",
|
||||
"device": "Enhet",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Sök efter enkätnamn",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Skapa ett läsbart engångs-ID och kopiera en signerad länk för det.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "Använd ett anpassat engångs-ID i URL:en.",
|
||||
"custom_start_point": "Anpassad startpunkt",
|
||||
"data_prefilling": "Dataförfyllning",
|
||||
"description": "Svar från dessa länkar kommer att vara anonyma",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "Deneme sürenizde 1 gün kaldı",
|
||||
"try_again": "Tekrar dene",
|
||||
"type": "Tür",
|
||||
"unknown_survey": "Bilinmeyen anket",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "Daha yüksek bir planla daha fazla çalışma alanının kilidini açın.",
|
||||
"update": "Güncelle",
|
||||
"updated": "Güncellendi",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "Bir survey seçin",
|
||||
"select_attribute": "Özellik Seçin",
|
||||
"select_attribute_key": "Özellik anahtarı seçin",
|
||||
"survey_response_created": "Yanıt oluşturuldu",
|
||||
"survey_viewed": "Survey görüntülendi",
|
||||
"survey_viewed_at": "Görüntülenme Tarihi",
|
||||
"system_attributes": "Sistem Özellikleri",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "Tamamlandı ✅",
|
||||
"country": "Ülke",
|
||||
"decrement_quotas": "Bu yanıtı içeren tüm kota limitlerini azalt",
|
||||
"delete_response": "Yanıtı sil",
|
||||
"delete_response_confirmation": "Bu işlem, tüm yanıtlar, etiketler, ekli belgeler ve yanıt meta verileri dahil olmak üzere survey yanıtını silecek.",
|
||||
"delete_response_quotas": "Yanıt bu survey'in kotalarına dahil. Kotaları nasıl yönetmek istiyorsunuz?",
|
||||
"device": "Cihaz",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "Survey adına göre ara",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "Okunabilir bir tek kullanımlık kimlik oluşturun ve bunun için imzalı bir bağlantı kopyalayın.",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "URL'de özel bir tek kullanımlık kimlik kullanın.",
|
||||
"custom_start_point": "Özel başlangıç noktası",
|
||||
"data_prefilling": "Veri ön doldurma",
|
||||
"description": "Bu bağlantılardan gelen yanıtlar anonim olacaktır",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "试用期还剩 1 天",
|
||||
"try_again": "再试一次",
|
||||
"type": "类型",
|
||||
"unknown_survey": "未知调查",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "升级套餐以解锁更多工作区。",
|
||||
"update": "更新",
|
||||
"updated": "已更新",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "选择一个调查",
|
||||
"select_attribute": "选择 属性",
|
||||
"select_attribute_key": "选择属性键",
|
||||
"survey_response_created": "回复已创建",
|
||||
"survey_viewed": "已查看调查",
|
||||
"survey_viewed_at": "查看时间",
|
||||
"system_attributes": "系统属性",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "完成 ✅",
|
||||
"country": "国家",
|
||||
"decrement_quotas": "减少所有配额限制,包括此回应",
|
||||
"delete_response": "删除回复",
|
||||
"delete_response_confirmation": "这 将 删除 调查 回应, 包括 所有 答案、 标签、 附件文档 和 回应元数据。",
|
||||
"delete_response_quotas": "该响应是 此 调查配额 的一部分。 您 希望 如何 处理 这些 配额?",
|
||||
"device": "设备",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "按 调查 名称 搜索",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "创建一个可读的一次性 ID,并复制其签名链接。",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "在 URL 中使用自定义一次性 ID。",
|
||||
"custom_start_point": "自定义 起点",
|
||||
"data_prefilling": "数据 预填充",
|
||||
"description": "来自 这些 link 的 响应 将是 匿名 的",
|
||||
|
||||
@@ -462,7 +462,6 @@
|
||||
"trial_one_day_remaining": "試用期剩餘 1 天",
|
||||
"try_again": "再試一次",
|
||||
"type": "類型",
|
||||
"unknown_survey": "未知問卷",
|
||||
"unlock_more_workspaces_with_a_higher_plan": "升級方案以解鎖更多工作區。",
|
||||
"update": "更新",
|
||||
"updated": "已更新",
|
||||
@@ -716,6 +715,7 @@
|
||||
"select_a_survey": "選擇問卷",
|
||||
"select_attribute": "選取屬性",
|
||||
"select_attribute_key": "選取屬性鍵值",
|
||||
"survey_response_created": "回應已建立",
|
||||
"survey_viewed": "已查看問卷",
|
||||
"survey_viewed_at": "查看時間",
|
||||
"system_attributes": "系統屬性",
|
||||
@@ -1891,6 +1891,7 @@
|
||||
"completed": "已完成 ✅",
|
||||
"country": "國家/地區",
|
||||
"decrement_quotas": "減少所有配額限制,包括此回應",
|
||||
"delete_response": "刪除回應",
|
||||
"delete_response_confirmation": "這將刪除調查響應,包括所有回答、標籤、附件文件以及響應元數據。",
|
||||
"delete_response_quotas": "回應 屬於 此 調查 的 配額 一部分 . 你 想 如何 處理 配額?",
|
||||
"device": "裝置",
|
||||
@@ -1918,10 +1919,10 @@
|
||||
"search_by_survey_name": "依問卷名稱搜尋",
|
||||
"share": {
|
||||
"anonymous_links": {
|
||||
"custom_single_use_id_description": "Create a readable single-use ID and copy a signed link for it.",
|
||||
"custom_single_use_id_description": "建立可讀的單次使用 ID,並複製其簽署連結。",
|
||||
"custom_single_use_id_placeholder": "CUSTOM-ID",
|
||||
"custom_single_use_id_required": "Enter a custom single-use ID.",
|
||||
"custom_single_use_id_title": "Use a custom single-use ID in the URL.",
|
||||
"custom_single_use_id_title": "在網址中使用自訂的單次使用 ID。",
|
||||
"custom_start_point": "自訂 開始 點",
|
||||
"data_prefilling": "資料預先填寫",
|
||||
"description": "從 這些 連結 獲得 的 回應 將是 匿名 的",
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import { TTag } from "@formbricks/types/tags";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { TagError } from "@/modules/projects/settings/types/tag";
|
||||
import { IdBadge } from "@/modules/ui/components/id-badge";
|
||||
import { Tag } from "@/modules/ui/components/tag";
|
||||
import { TagsCombobox } from "@/modules/ui/components/tags-combobox";
|
||||
import { createTagAction, createTagToResponseAction, deleteTagOnResponseAction } from "../actions";
|
||||
@@ -160,6 +161,7 @@ export const ResponseTagsWrapper: React.FC<ResponseTagsWrapperProps> = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<IdBadge id={responseId} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+3
-4
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { getLanguageLabel } from "@formbricks/i18n-utils/src/utils";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TUserLocale } from "@formbricks/types/user";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
||||
|
||||
interface InfoIconButtonProps {
|
||||
@@ -25,11 +26,9 @@ const InfoIconButton = ({
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className="flex h-4 w-4 items-center justify-center rounded text-slate-500 hover:text-slate-700"
|
||||
aria-label={ariaLabel}>
|
||||
<Button variant="outline" size="icon" aria-label={ariaLabel}>
|
||||
<Icon className="h-4 w-4" />
|
||||
</button>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent avoidCollisions align="start" side="bottom" className={maxWidth}>
|
||||
{tooltipContent}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
import { ReactNode, useMemo, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
@@ -16,7 +16,12 @@ import { deleteResponseAction, getResponseAction } from "./actions";
|
||||
import { ResponseTagsWrapper } from "./components/ResponseTagsWrapper";
|
||||
import { SingleResponseCardBody } from "./components/SingleResponseCardBody";
|
||||
import { SingleResponseCardHeader } from "./components/SingleResponseCardHeader";
|
||||
import { isValidValue } from "./util";
|
||||
import { isSubmissionTimeMoreThan5Minutes, isValidValue } from "./util";
|
||||
|
||||
export interface SingleResponseCardHeaderRenderProps {
|
||||
onDeleteClick: () => void;
|
||||
canResponseBeDeleted: boolean;
|
||||
}
|
||||
|
||||
interface SingleResponseCardProps {
|
||||
survey: TSurvey;
|
||||
@@ -29,6 +34,11 @@ interface SingleResponseCardProps {
|
||||
isReadOnly: boolean;
|
||||
setSelectedResponseId?: (responseId: string | null) => void;
|
||||
locale: TUserLocale;
|
||||
/**
|
||||
* Optional render-prop to replace the default header. Receives helpers to
|
||||
* trigger the (shared) delete dialog so callers don't have to reimplement it.
|
||||
*/
|
||||
renderHeader?: (props: SingleResponseCardHeaderRenderProps) => ReactNode;
|
||||
}
|
||||
|
||||
export const SingleResponseCard = ({
|
||||
@@ -42,7 +52,8 @@ export const SingleResponseCard = ({
|
||||
isReadOnly,
|
||||
setSelectedResponseId,
|
||||
locale,
|
||||
}: SingleResponseCardProps) => {
|
||||
renderHeader,
|
||||
}: Readonly<SingleResponseCardProps>) => {
|
||||
const hasQuotas = (response?.quotas && response.quotas.length > 0) ?? false;
|
||||
const [decrementQuotas, setDecrementQuotas] = useState(hasQuotas);
|
||||
const { t } = useTranslation();
|
||||
@@ -128,19 +139,30 @@ export const SingleResponseCard = ({
|
||||
}
|
||||
};
|
||||
|
||||
const canResponseBeDeleted = response.finished
|
||||
? true
|
||||
: isSubmissionTimeMoreThan5Minutes(response.updatedAt);
|
||||
|
||||
return (
|
||||
<div className="group relative">
|
||||
<div className="relative z-20 my-6 rounded-xl border border-slate-200 bg-white shadow-sm transition-all">
|
||||
<SingleResponseCardHeader
|
||||
pageType="response"
|
||||
response={response}
|
||||
survey={survey}
|
||||
environment={environment}
|
||||
user={user}
|
||||
isReadOnly={isReadOnly}
|
||||
setDeleteDialogOpen={setDeleteDialogOpen}
|
||||
locale={locale}
|
||||
/>
|
||||
<div className="relative z-20 rounded-xl border border-slate-200 bg-white shadow-sm transition-all">
|
||||
{renderHeader ? (
|
||||
renderHeader({
|
||||
onDeleteClick: () => setDeleteDialogOpen(true),
|
||||
canResponseBeDeleted,
|
||||
})
|
||||
) : (
|
||||
<SingleResponseCardHeader
|
||||
pageType="response"
|
||||
response={response}
|
||||
survey={survey}
|
||||
environment={environment}
|
||||
user={user}
|
||||
isReadOnly={isReadOnly}
|
||||
setDeleteDialogOpen={setDeleteDialogOpen}
|
||||
locale={locale}
|
||||
/>
|
||||
)}
|
||||
|
||||
<SingleResponseCardBody
|
||||
survey={survey}
|
||||
|
||||
@@ -18,8 +18,8 @@ import { DisplayCard } from "./display-card";
|
||||
import { ResponseSurveyCard } from "./response-survey-card";
|
||||
|
||||
type TTimelineItem =
|
||||
| { type: "display"; data: Pick<TDisplay, "id" | "createdAt" | "surveyId"> }
|
||||
| { type: "response"; data: TResponseWithQuotas };
|
||||
| { type: "display"; data: Pick<TDisplay, "id" | "createdAt" | "surveyId">; survey: TSurvey }
|
||||
| { type: "response"; data: TResponseWithQuotas; survey: TSurvey };
|
||||
|
||||
interface ActivityTimelineProps {
|
||||
surveys: TSurvey[];
|
||||
@@ -41,7 +41,7 @@ export const ActivityTimeline = ({
|
||||
environmentTags,
|
||||
locale,
|
||||
projectPermission,
|
||||
}: ActivityTimelineProps) => {
|
||||
}: Readonly<ActivityTimelineProps>) => {
|
||||
const { t } = useTranslation();
|
||||
const [responses, setResponses] = useState(initialResponses);
|
||||
const [isReversed, setIsReversed] = useState(false);
|
||||
@@ -66,16 +66,20 @@ export const ActivityTimeline = ({
|
||||
setResponses((prev) => prev.map((r) => (r.id === responseId ? updatedResponse : r)));
|
||||
};
|
||||
|
||||
const timelineItems = useMemo(() => {
|
||||
const displayItems: TTimelineItem[] = displays.map((d) => ({
|
||||
type: "display" as const,
|
||||
data: d,
|
||||
}));
|
||||
const surveyById = useMemo(() => {
|
||||
return new Map(surveys.map((s) => [s.id, s]));
|
||||
}, [surveys]);
|
||||
|
||||
const responseItems: TTimelineItem[] = responses.map((r) => ({
|
||||
type: "response" as const,
|
||||
data: r,
|
||||
}));
|
||||
const timelineItems = useMemo(() => {
|
||||
const displayItems: TTimelineItem[] = displays.flatMap((d) => {
|
||||
const survey = surveyById.get(d.surveyId);
|
||||
return survey ? [{ type: "display" as const, data: d, survey }] : [];
|
||||
});
|
||||
|
||||
const responseItems: TTimelineItem[] = responses.flatMap((r) => {
|
||||
const survey = surveyById.get(r.surveyId);
|
||||
return survey ? [{ type: "response" as const, data: r, survey }] : [];
|
||||
});
|
||||
|
||||
const merged = [...displayItems, ...responseItems].sort((a, b) => {
|
||||
const aTime = new Date(a.data.createdAt).getTime();
|
||||
@@ -84,7 +88,7 @@ export const ActivityTimeline = ({
|
||||
});
|
||||
|
||||
return isReversed ? [...merged].reverse() : merged;
|
||||
}, [displays, responses, isReversed]);
|
||||
}, [displays, responses, surveyById, isReversed]);
|
||||
|
||||
const toggleSort = () => {
|
||||
setIsReversed((prev) => !prev);
|
||||
@@ -112,7 +116,7 @@ export const ActivityTimeline = ({
|
||||
<DisplayCard
|
||||
key={`display-${item.data.id}`}
|
||||
display={item.data}
|
||||
surveys={surveys}
|
||||
survey={item.survey}
|
||||
environmentId={environment.id}
|
||||
locale={locale}
|
||||
/>
|
||||
@@ -120,7 +124,7 @@ export const ActivityTimeline = ({
|
||||
<ResponseSurveyCard
|
||||
key={`response-${item.data.id}`}
|
||||
response={item.data}
|
||||
surveys={surveys}
|
||||
survey={item.survey}
|
||||
user={user}
|
||||
environmentTags={environmentTags}
|
||||
environment={environment}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { LinkIcon, PencilIcon, TrashIcon } from "lucide-react";
|
||||
import { LinkIcon, PencilIcon, RefreshCwIcon, TrashIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useState, useTransition } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TContactAttributeDataType, TContactAttributeKey } from "@formbricks/types/contact-attribute-key";
|
||||
@@ -46,6 +46,13 @@ export const ContactControlBar = ({
|
||||
const [isDeletingPerson, setIsDeletingPerson] = useState(false);
|
||||
const [isGenerateLinkModalOpen, setIsGenerateLinkModalOpen] = useState(false);
|
||||
const [isEditAttributesModalOpen, setIsEditAttributesModalOpen] = useState(false);
|
||||
const [isRefreshing, startRefreshTransition] = useTransition();
|
||||
|
||||
const handleRefresh = () => {
|
||||
startRefreshTransition(() => {
|
||||
router.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeletePerson = async () => {
|
||||
setIsDeletingPerson(true);
|
||||
@@ -62,18 +69,22 @@ export const ContactControlBar = ({
|
||||
setDeleteDialogOpen(false);
|
||||
};
|
||||
|
||||
if (isReadOnly) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const iconActions = [
|
||||
{
|
||||
icon: RefreshCwIcon,
|
||||
tooltip: t("common.refresh"),
|
||||
onClick: handleRefresh,
|
||||
isVisible: true,
|
||||
disabled: isRefreshing,
|
||||
iconClassName: isRefreshing ? "animate-spin" : undefined,
|
||||
},
|
||||
{
|
||||
icon: PencilIcon,
|
||||
tooltip: t("environments.contacts.edit_attributes"),
|
||||
onClick: () => {
|
||||
setIsEditAttributesModalOpen(true);
|
||||
},
|
||||
isVisible: true,
|
||||
isVisible: !isReadOnly,
|
||||
},
|
||||
{
|
||||
icon: LinkIcon,
|
||||
@@ -81,7 +92,7 @@ export const ContactControlBar = ({
|
||||
onClick: () => {
|
||||
setIsGenerateLinkModalOpen(true);
|
||||
},
|
||||
isVisible: true,
|
||||
isVisible: !isReadOnly,
|
||||
},
|
||||
{
|
||||
icon: TrashIcon,
|
||||
@@ -89,7 +100,7 @@ export const ContactControlBar = ({
|
||||
onClick: () => {
|
||||
setDeleteDialogOpen(true);
|
||||
},
|
||||
isVisible: true,
|
||||
isVisible: !isReadOnly,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@ import { timeSince } from "@/lib/time";
|
||||
|
||||
interface DisplayCardProps {
|
||||
display: Pick<TDisplay, "id" | "createdAt" | "surveyId">;
|
||||
surveys: TSurvey[];
|
||||
survey: TSurvey;
|
||||
environmentId: string;
|
||||
locale: TUserLocale;
|
||||
}
|
||||
|
||||
export const DisplayCard = ({ display, surveys, environmentId, locale }: DisplayCardProps) => {
|
||||
export const DisplayCard = ({ display, survey, environmentId, locale }: Readonly<DisplayCardProps>) => {
|
||||
const { t } = useTranslation();
|
||||
const survey = surveys.find((s) => s.id === display.surveyId);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
|
||||
@@ -27,15 +26,11 @@ export const DisplayCard = ({ display, surveys, environmentId, locale }: Display
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-slate-500">{t("environments.contacts.survey_viewed")}</p>
|
||||
{survey ? (
|
||||
<Link
|
||||
href={`/environments/${environmentId}/surveys/${survey.id}/summary`}
|
||||
className="text-sm font-medium text-slate-700 hover:underline">
|
||||
{survey.name}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="text-sm font-medium text-slate-500">{t("common.unknown_survey")}</span>
|
||||
)}
|
||||
<Link
|
||||
href={`/environments/${environmentId}/surveys/${survey.id}/summary`}
|
||||
className="text-sm font-medium text-slate-700 hover:underline">
|
||||
{survey.name}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-sm text-slate-500">{timeSince(display.createdAt.toString(), locale)}</span>
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { MessageSquareTextIcon, TrashIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TEnvironment } from "@formbricks/types/environment";
|
||||
import { TResponseWithQuotas } from "@formbricks/types/responses";
|
||||
import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { TTag } from "@formbricks/types/tags";
|
||||
import { TUser, TUserLocale } from "@formbricks/types/user";
|
||||
import { timeSince } from "@/lib/time";
|
||||
import { replaceHeadlineRecall } from "@/lib/utils/recall";
|
||||
import { SingleResponseCard } from "@/modules/analysis/components/SingleResponseCard";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/modules/ui/components/tooltip";
|
||||
|
||||
interface ResponseSurveyCardProps {
|
||||
response: TResponseWithQuotas;
|
||||
surveys: TSurvey[];
|
||||
survey: TSurvey;
|
||||
user: TUser;
|
||||
environmentTags: TTag[];
|
||||
environment: TEnvironment;
|
||||
@@ -22,7 +29,7 @@ interface ResponseSurveyCardProps {
|
||||
|
||||
export const ResponseSurveyCard = ({
|
||||
response,
|
||||
surveys,
|
||||
survey,
|
||||
user,
|
||||
environmentTags,
|
||||
environment,
|
||||
@@ -30,22 +37,74 @@ export const ResponseSurveyCard = ({
|
||||
updateResponse,
|
||||
locale,
|
||||
isReadOnly,
|
||||
}: ResponseSurveyCardProps) => {
|
||||
const survey = surveys.find((s) => s.id === response.surveyId);
|
||||
}: Readonly<ResponseSurveyCardProps>) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!survey) return null;
|
||||
const surveyWithReplacedRecall = useMemo(() => replaceHeadlineRecall(survey, "default"), [survey]);
|
||||
|
||||
const showDeleteButton = !!user && !isReadOnly;
|
||||
|
||||
return (
|
||||
<SingleResponseCard
|
||||
survey={surveyWithReplacedRecall}
|
||||
response={response}
|
||||
survey={replaceHeadlineRecall(survey, "default")}
|
||||
user={user}
|
||||
environmentTags={environmentTags}
|
||||
environment={environment}
|
||||
updateResponseList={updateResponseList}
|
||||
updateResponse={updateResponse}
|
||||
environmentTags={environmentTags}
|
||||
isReadOnly={isReadOnly}
|
||||
updateResponse={updateResponse}
|
||||
updateResponseList={updateResponseList}
|
||||
locale={locale}
|
||||
renderHeader={({ onDeleteClick, canResponseBeDeleted }) => (
|
||||
<div className="flex items-center justify-between p-4">
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-slate-100">
|
||||
<MessageSquareTextIcon className="h-4 w-4 text-slate-600" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-xs text-slate-500">{t("environments.contacts.survey_response_created")}</p>
|
||||
<Link
|
||||
href={`/environments/${environment.id}/surveys/${survey.id}/summary`}
|
||||
className="block truncate text-sm font-medium text-slate-700 hover:underline">
|
||||
{survey.name}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 text-sm text-slate-500">
|
||||
<time className="px-1" dateTime={response.createdAt.toString()}>
|
||||
{timeSince(response.createdAt.toString(), locale)}
|
||||
</time>
|
||||
{showDeleteButton &&
|
||||
(canResponseBeDeleted ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={onDeleteClick}
|
||||
aria-label={t("environments.surveys.responses.delete_response")}>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
) : (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled
|
||||
className="text-slate-400"
|
||||
aria-label={t("environments.surveys.responses.delete_response")}>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="left">
|
||||
{t("environments.surveys.responses.this_response_is_in_progress")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ interface IconAction {
|
||||
onClick?: () => void;
|
||||
isVisible?: boolean;
|
||||
disabled?: boolean;
|
||||
iconClassName?: string;
|
||||
}
|
||||
|
||||
interface IconBarProps {
|
||||
@@ -16,30 +17,30 @@ interface IconBarProps {
|
||||
}
|
||||
|
||||
export const IconBar = ({ actions }: IconBarProps) => {
|
||||
if (actions.length === 0) return null;
|
||||
const visibleActions = actions.filter((action) => action.isVisible);
|
||||
|
||||
if (visibleActions.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-center divide-x rounded-md border border-slate-300 bg-white"
|
||||
role="toolbar"
|
||||
aria-label="Action buttons">
|
||||
{actions
|
||||
.filter((action) => action.isVisible)
|
||||
.map((action, index) => (
|
||||
<span key={`${action.tooltip}-${index}`}>
|
||||
<TooltipRenderer tooltipContent={action.tooltip}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="border-none hover:bg-slate-50"
|
||||
size="icon"
|
||||
onClick={action.onClick}
|
||||
disabled={action.disabled}
|
||||
aria-label={action.tooltip}>
|
||||
<action.icon />
|
||||
</Button>
|
||||
</TooltipRenderer>
|
||||
</span>
|
||||
))}
|
||||
{visibleActions.map((action, index) => (
|
||||
<span key={`${action.tooltip}-${index}`}>
|
||||
<TooltipRenderer tooltipContent={action.tooltip}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="border-none hover:bg-slate-50"
|
||||
size="icon"
|
||||
onClick={action.onClick}
|
||||
disabled={action.disabled}
|
||||
aria-label={action.tooltip}>
|
||||
<action.icon className={action.iconClassName} />
|
||||
</Button>
|
||||
</TooltipRenderer>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user