@@ -27,6 +27,7 @@ export default function DocsFeedback() {
|
||||
<div className="ml-4 inline-flex space-x-3">
|
||||
{["Yes 👍", " No 👎"].map((option) => (
|
||||
<PopoverTrigger
|
||||
key={option}
|
||||
className="rounded border border-slate-200 bg-slate-50 px-4 py-2 text-slate-900 hover:bg-slate-100 hover:text-slate-600 focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 dark:hover:text-slate-300"
|
||||
onClick={async () => {
|
||||
const id = await handleFeedbackSubmit(option, router.asPath);
|
||||
@@ -42,7 +43,7 @@ export default function DocsFeedback() {
|
||||
value={freeText}
|
||||
onChange={(e) => setFreeText(e.target.value)}
|
||||
placeholder="Please explain why..."
|
||||
className="w-full rounded-md bg-white text-sm text-slate-900 dark:bg-slate-600 dark:text-slate-200 dark:placeholder:text-slate-200"
|
||||
className="focus:border-brand-dark focus:ring-brand-dark mb-2 w-full rounded-md bg-white text-sm text-slate-900 dark:bg-slate-600 dark:text-slate-200 dark:placeholder:text-slate-200"
|
||||
/>
|
||||
<div className="text-right">
|
||||
<Button
|
||||
|
||||
@@ -4,6 +4,8 @@ import CrowdLogoDark from "@/images/clients/crowd-logo-dark.svg";
|
||||
import CrowdLogoLight from "@/images/clients/crowd-logo-light.svg";
|
||||
import StackOceanLogoDark from "@/images/clients/stack-ocean-dark.png";
|
||||
import StackOceanLogoLight from "@/images/clients/stack-ocean-light.png";
|
||||
import NILogoLight from "@/images/clients/niLogoWhite.svg";
|
||||
import NILogoDark from "@/images/clients/niLogoDark.svg";
|
||||
import AnimationFallback from "@/public/animations/fallback-image-open-source-feedback-software.jpg";
|
||||
import { Button } from "@formbricks/ui";
|
||||
import { usePlausible } from "next-plausible";
|
||||
@@ -38,11 +40,11 @@ export default function Hero({}: Props) {
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="mx-auto mt-5 max-w-2xl items-center space-x-8 sm:flex sm:justify-center md:mt-8">
|
||||
<p className="hidden whitespace-nowrap pt-1 text-xs text-slate-400 dark:text-slate-500 md:block">
|
||||
<div className="mx-auto mt-5 max-w-3xl items-center space-x-8 sm:flex sm:justify-center md:mt-8">
|
||||
<p className="hidden whitespace-nowrap pt-3 text-xs text-slate-400 dark:text-slate-500 md:block">
|
||||
Trusted by
|
||||
</p>
|
||||
<div className="grid grid-cols-4 gap-8 pt-2">
|
||||
<div className="grid grid-cols-5 items-center gap-8 pt-2">
|
||||
<Image
|
||||
src={CalLogoLight}
|
||||
alt="Cal Logo"
|
||||
@@ -73,16 +75,28 @@ export default function Hero({}: Props) {
|
||||
className="rounded-lg pb-1 opacity-50 hover:opacity-100"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={NILogoDark}
|
||||
alt="Neverinstall Logo"
|
||||
className="block pb-1 opacity-50 hover:opacity-100 dark:hidden"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={NILogoLight}
|
||||
alt="Neverinstall Logo"
|
||||
className="hidden pb-1 opacity-50 hover:opacity-100 dark:block"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={StackOceanLogoLight}
|
||||
alt="StackOcean Logo"
|
||||
className="block rounded-lg pb-1 opacity-50 hover:opacity-100 dark:hidden"
|
||||
className="block pb-1 opacity-50 hover:opacity-100 dark:hidden"
|
||||
width={200}
|
||||
/>
|
||||
<Image
|
||||
src={StackOceanLogoDark}
|
||||
alt="StakcOcean Logo"
|
||||
className="hidden rounded-lg pb-1 opacity-50 hover:opacity-100 dark:block"
|
||||
className="hidden pb-1 opacity-50 hover:opacity-100 dark:block"
|
||||
width={200}
|
||||
/>
|
||||
</div>
|
||||
|
||||
20
apps/formbricks-com/images/clients/niLogoDark.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<svg width="1004" height="311" viewBox="0 0 1004 311" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M104.198 125.141L0.466736 187.097V62.9373L104.198 125.141Z" fill="#5B29FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M104 125.204L206.539 63L310.27 125.204V247.871L206.539 310.075V187.409L104 125.204Z" fill="#2962FF"/>
|
||||
<path d="M104.198 0.00195312L0.466736 62.9526L104.198 125.157L206.737 62.9526L104.198 0.00195312Z" fill="#FFC629"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.466736 62.9526L104.198 125.157L206.737 62.9526L104.198 0.00195312L0.466736 62.9526ZM19.8215 62.9004L104.17 113.481L187.549 62.9006L104.17 11.7126L19.8215 62.9004Z" fill="#FAFAFA"/>
|
||||
<path d="M104.189 113.486V11.7527L19.8417 62.9369L104.189 113.486Z" fill="#FFBC00"/>
|
||||
<path d="M418.241 188.759H450.845V301.364H418.241V188.759ZM434.543 173.061C428.552 173.061 423.675 171.317 419.913 167.829C416.151 164.34 414.27 160.015 414.27 154.852C414.27 149.689 416.151 145.363 419.913 141.875C423.675 138.386 428.552 136.642 434.543 136.642C440.535 136.642 445.411 138.317 449.173 141.666C452.935 145.014 454.816 149.201 454.816 154.224C454.816 159.666 452.935 164.201 449.173 167.829C445.411 171.317 440.535 173.061 434.543 173.061Z" fill="#192137"/>
|
||||
<path d="M538.998 187.084C552.931 187.084 564.147 191.271 572.647 199.643C581.285 208.015 585.605 220.434 585.605 236.899V301.364H553.001V241.922C553.001 232.992 551.05 226.364 547.149 222.038C543.247 217.573 537.604 215.34 530.22 215.34C521.999 215.34 515.45 217.922 510.574 223.085C505.697 228.108 503.259 235.643 503.259 245.69V301.364H470.655V188.759H501.796V201.945C506.115 197.201 511.479 193.573 517.889 191.061C524.298 188.41 531.334 187.084 538.998 187.084Z" fill="#192137"/>
|
||||
<path d="M646.717 303.039C637.382 303.039 628.256 301.922 619.338 299.69C610.421 297.318 603.315 294.388 598.02 290.899L608.888 267.457C613.904 270.666 619.965 273.318 627.071 275.411C634.177 277.364 641.144 278.341 647.971 278.341C661.765 278.341 668.662 274.922 668.662 268.085C668.662 264.876 666.781 262.573 663.019 261.178C659.257 259.783 653.475 258.597 645.672 257.62C636.476 256.224 628.883 254.62 622.891 252.806C616.9 250.992 611.675 247.783 607.216 243.178C602.897 238.573 600.737 232.015 600.737 223.503C600.737 216.387 602.758 210.108 606.798 204.666C610.978 199.085 616.97 194.759 624.772 191.689C632.714 188.619 642.05 187.084 652.778 187.084C660.72 187.084 668.593 187.991 676.395 189.805C684.337 191.48 690.886 193.852 696.042 196.922L685.173 220.154C675.281 214.573 664.482 211.782 652.778 211.782C645.812 211.782 640.587 212.759 637.103 214.713C633.62 216.666 631.878 219.178 631.878 222.248C631.878 225.736 633.759 228.178 637.521 229.573C641.283 230.968 647.275 232.294 655.495 233.55C664.691 235.085 672.215 236.759 678.068 238.573C683.919 240.248 689.005 243.387 693.324 247.992C697.644 252.597 699.803 259.015 699.803 267.248C699.803 274.225 697.713 280.434 693.533 285.876C689.353 291.318 683.223 295.574 675.141 298.643C667.199 301.574 657.725 303.039 646.717 303.039Z" fill="#192137"/>
|
||||
<path d="M786.173 295.922C782.968 298.295 778.997 300.108 774.26 301.364C769.662 302.481 764.785 303.039 759.63 303.039C746.254 303.039 735.873 299.62 728.489 292.783C721.243 285.946 717.621 275.899 717.621 262.643V216.387H700.274V191.271H717.621V163.852H750.225V191.271H778.231V216.387H750.225V262.225C750.225 266.969 751.409 270.666 753.778 273.318C756.286 275.829 759.769 277.085 764.228 277.085C769.383 277.085 773.772 275.69 777.395 272.899L786.173 295.922Z" fill="#192137"/>
|
||||
<path d="M837.288 187.084C854.705 187.084 868.081 191.271 877.416 199.643C886.751 207.875 891.419 220.364 891.419 237.108V301.364H860.905V287.341C854.774 297.806 843.349 303.039 826.629 303.039C817.99 303.039 810.466 301.574 804.057 298.643C797.787 295.713 792.98 291.667 789.636 286.504C786.292 281.341 784.62 275.48 784.62 268.922C784.62 258.457 788.521 250.224 796.324 244.224C804.266 238.224 816.458 235.224 832.899 235.224H858.815C858.815 228.108 856.655 222.666 852.336 218.899C848.017 214.992 841.538 213.038 832.899 213.038C826.908 213.038 820.986 214.015 815.134 215.968C809.421 217.782 804.545 220.294 800.504 223.503L788.8 200.689C794.931 196.364 802.246 193.015 810.745 190.643C819.384 188.271 828.231 187.084 837.288 187.084ZM834.78 281.062C840.353 281.062 845.3 279.806 849.619 277.294C853.938 274.643 857.004 270.806 858.815 265.783V254.271H836.452C823.076 254.271 816.388 258.666 816.388 267.457C816.388 271.643 817.99 274.992 821.195 277.504C824.539 279.876 829.067 281.062 834.78 281.062Z" fill="#192137"/>
|
||||
<path d="M908.387 146.061H940.991V301.364H908.387V146.061Z" fill="#192137"/>
|
||||
<path d="M960.8 146.061H993.404V301.364H960.8V146.061Z" fill="#192137"/>
|
||||
<path d="M419.913 167.738C423.675 171.227 428.552 172.971 434.543 172.971C440.535 172.971 445.411 171.227 449.173 167.738C452.935 164.11 454.816 159.576 454.816 154.134C454.816 149.11 452.935 144.924 449.173 141.575C445.411 138.227 440.535 136.552 434.543 136.552C428.552 136.552 423.675 138.296 419.913 141.785C416.151 145.273 414.27 149.599 414.27 154.762C414.27 159.924 416.151 164.25 419.913 167.738Z" fill="#192137"/>
|
||||
<path d="M482.602 7.03833C496.533 7.03833 507.748 11.2109 516.245 19.5559C524.883 27.9009 529.201 40.2794 529.201 56.6914V120.948H496.603V61.6984C496.603 52.797 494.652 46.1905 490.752 41.8789C486.851 37.4282 481.209 35.2029 473.825 35.2029C465.606 35.2029 459.059 37.7759 454.183 42.922C449.307 47.9291 446.869 55.4396 446.869 65.4537V120.948H414.27V8.70733H445.406V21.8508C449.725 17.1219 455.088 13.5057 461.496 11.0022C467.905 8.35962 474.94 7.03833 482.602 7.03833Z" fill="#192137"/>
|
||||
<path d="M660.517 65.245C660.517 65.6623 660.308 68.5831 659.89 74.0073H574.841C576.373 80.9616 579.995 86.4554 585.707 90.4888C591.419 94.5223 598.523 96.539 607.021 96.539C612.872 96.539 618.027 95.7045 622.485 94.0355C627.082 92.2274 631.331 89.4457 635.232 85.6904L652.576 104.467C641.988 116.567 626.525 122.617 606.186 122.617C593.508 122.617 582.294 120.183 572.542 115.315C562.79 110.308 555.268 103.424 549.974 94.6613C544.68 85.899 542.033 75.9545 542.033 64.8278C542.033 53.8401 544.61 43.9652 549.765 35.2029C555.059 26.3015 562.233 19.4168 571.288 14.5489C580.483 9.54184 590.722 7.03833 602.006 7.03833C613.012 7.03833 622.972 9.40276 631.888 14.1316C640.804 18.8605 647.77 25.6756 652.785 34.577C657.939 43.3393 660.517 53.562 660.517 65.245ZM602.215 31.6562C594.832 31.6562 588.632 33.7425 583.617 37.915C578.602 42.0875 575.537 47.79 574.423 55.0224H629.799C628.684 47.9291 625.619 42.2962 620.604 38.1236C615.589 33.812 609.459 31.6562 602.215 31.6562Z" fill="#192137"/>
|
||||
<path d="M791.767 8.70733L744.331 120.948H710.688L663.462 8.70733H697.105L728.241 85.0645L760.422 8.70733H791.767Z" fill="#192137"/>
|
||||
<path d="M912.132 65.245C912.132 65.6623 911.923 68.5831 911.506 74.0073H826.457C827.989 80.9616 831.611 86.4554 837.323 90.4888C843.034 94.5223 850.139 96.539 858.637 96.539C864.488 96.539 869.643 95.7045 874.101 94.0355C878.698 92.2274 882.947 89.4457 886.848 85.6904L904.192 104.467C893.604 116.567 878.141 122.617 857.801 122.617C845.124 122.617 833.91 120.183 824.158 115.315C814.406 110.308 806.883 103.424 801.59 94.6613C796.296 85.899 793.649 75.9545 793.649 64.8278C793.649 53.8401 796.226 43.9652 801.381 35.2029C806.674 26.3015 813.849 19.4168 822.904 14.5489C832.099 9.54184 842.338 7.03833 853.622 7.03833C864.628 7.03833 874.588 9.40276 883.504 14.1316C892.42 18.8605 899.386 25.6756 904.401 34.577C909.555 43.3393 912.132 53.562 912.132 65.245ZM853.831 31.6562C846.448 31.6562 840.248 33.7425 835.233 37.915C830.218 42.0875 827.153 47.79 826.039 55.0224H881.415C880.3 47.9291 877.235 42.2962 872.22 38.1236C867.205 33.812 861.075 31.6562 853.831 31.6562Z" fill="#192137"/>
|
||||
<path d="M964.971 23.5198C968.872 18.0955 974.096 13.9925 980.644 11.2109C987.331 8.42917 994.993 7.03833 1003.63 7.03833V37.0805C1000.01 36.8023 997.57 36.6633 996.316 36.6633C986.982 36.6633 979.669 39.3059 974.375 44.591C969.081 49.7372 966.434 57.5259 966.434 67.9572V120.948H933.836V8.70733H964.971V23.5198Z" fill="#192137"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
20
apps/formbricks-com/images/clients/niLogoWhite.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<svg width="1004" height="311" viewBox="0 0 1004 311" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M104.272 125.141L0.541077 187.097V62.9373L104.272 125.141Z" fill="#6A51F5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M104.271 125.131L206.81 62.9271L310.541 125.131V247.798L206.81 310.002V187.336L104.271 125.131Z" fill="#386DFF"/>
|
||||
<path d="M104.272 0.00195312L0.541077 62.9526L104.272 125.157L206.811 62.9526L104.272 0.00195312Z" fill="#FFC629"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.541077 62.9526L104.272 125.157L206.811 62.9526L104.272 0.00195312L0.541077 62.9526ZM19.8959 62.9004L104.244 113.481L187.623 62.9006L104.244 11.7126L19.8959 62.9004Z" fill="#FAFAFA"/>
|
||||
<path d="M104.263 113.486V11.7527L19.9161 62.9369L104.263 113.486Z" fill="#FFBC00"/>
|
||||
<path d="M418.512 188.723H451.116V301.328H418.512V188.723ZM434.814 173.025C428.822 173.025 423.946 171.281 420.184 167.792C416.422 164.304 414.541 159.978 414.541 154.815C414.541 149.652 416.422 145.327 420.184 141.838C423.946 138.35 428.822 136.606 434.814 136.606C440.805 136.606 445.682 138.28 449.444 141.629C453.206 144.978 455.087 149.164 455.087 154.187C455.087 159.629 453.206 164.164 449.444 167.792C445.682 171.281 440.805 173.025 434.814 173.025Z" fill="#FAFAFA"/>
|
||||
<path d="M539.268 187.048C553.201 187.048 564.418 191.234 572.917 199.606C581.556 207.978 585.875 220.397 585.875 236.862V301.328H553.271V241.886C553.271 232.955 551.32 226.327 547.419 222.002C543.518 217.537 537.875 215.304 530.49 215.304C522.269 215.304 515.721 217.886 510.844 223.048C505.967 228.072 503.529 235.607 503.529 245.653V301.328H470.925V188.723H502.066V201.909C506.385 197.164 511.75 193.537 518.159 191.025C524.568 188.374 531.605 187.048 539.268 187.048Z" fill="#FAFAFA"/>
|
||||
<path d="M646.988 303.002C637.653 303.002 628.526 301.886 619.609 299.654C610.692 297.281 603.586 294.351 598.291 290.863L609.159 267.421C614.175 270.63 620.236 273.281 627.342 275.374C634.448 277.328 641.415 278.305 648.242 278.305C662.036 278.305 668.933 274.886 668.933 268.049C668.933 264.839 667.052 262.537 663.29 261.142C659.528 259.746 653.746 258.56 645.943 257.583C636.747 256.188 629.153 254.583 623.162 252.769C617.171 250.955 611.946 247.746 607.487 243.141C603.168 238.537 601.008 231.979 601.008 223.467C601.008 216.351 603.028 210.072 607.069 204.63C611.249 199.048 617.24 194.723 625.043 191.653C632.985 188.583 642.32 187.048 653.049 187.048C660.991 187.048 668.863 187.955 676.666 189.769C684.608 191.443 691.157 193.816 696.312 196.885L685.444 220.118C675.551 214.537 664.753 211.746 653.049 211.746C646.082 211.746 640.857 212.723 637.374 214.676C633.891 216.63 632.149 219.141 632.149 222.211C632.149 225.7 634.03 228.141 637.792 229.537C641.554 230.932 647.545 232.258 655.766 233.514C664.962 235.048 672.486 236.723 678.338 238.537C684.19 240.211 689.276 243.351 693.595 247.955C697.914 252.56 700.074 258.979 700.074 267.211C700.074 274.188 697.984 280.398 693.804 285.839C689.624 291.281 683.493 295.537 675.412 298.607C667.47 301.537 657.995 303.002 646.988 303.002Z" fill="#FAFAFA"/>
|
||||
<path d="M786.443 295.886C783.239 298.258 779.268 300.072 774.53 301.328C769.932 302.444 765.056 303.002 759.9 303.002C746.524 303.002 736.144 299.584 728.759 292.747C721.514 285.909 717.891 275.863 717.891 262.607V216.351H700.544V191.234H717.891V163.815H750.495V191.234H778.501V216.351H750.495V262.188C750.495 266.932 751.68 270.63 754.048 273.281C756.556 275.793 760.04 277.049 764.498 277.049C769.654 277.049 774.043 275.653 777.665 272.863L786.443 295.886Z" fill="#FAFAFA"/>
|
||||
<path d="M837.559 187.048C854.975 187.048 868.351 191.234 877.687 199.606C887.022 207.839 891.69 220.327 891.69 237.072V301.328H861.176V287.305C855.045 297.77 843.62 303.002 826.9 303.002C818.261 303.002 810.737 301.537 804.328 298.607C798.057 295.677 793.251 291.63 789.907 286.467C786.563 281.305 784.89 275.444 784.89 268.886C784.89 258.421 788.792 250.188 796.595 244.188C804.536 238.188 816.728 235.188 833.17 235.188H859.086C859.086 228.072 856.926 222.63 852.607 218.862C848.287 214.955 841.808 213.002 833.17 213.002C827.178 213.002 821.257 213.979 815.405 215.932C809.692 217.746 804.815 220.258 800.775 223.467L789.071 200.653C795.201 196.327 802.516 192.978 811.016 190.606C819.654 188.234 828.502 187.048 837.559 187.048ZM835.051 281.025C840.624 281.025 845.57 279.77 849.89 277.258C854.209 274.607 857.274 270.77 859.086 265.746V254.235H836.723C823.346 254.235 816.659 258.63 816.659 267.421C816.659 271.607 818.261 274.956 821.466 277.467C824.81 279.839 829.338 281.025 835.051 281.025Z" fill="#FAFAFA"/>
|
||||
<path d="M908.658 146.025H941.262V301.328H908.658V146.025Z" fill="#FAFAFA"/>
|
||||
<path d="M961.071 146.025H993.675V301.328H961.071V146.025Z" fill="#FAFAFA"/>
|
||||
<path d="M420.184 167.702C423.946 171.19 428.822 172.935 434.814 172.935C440.805 172.935 445.682 171.19 449.444 167.702C453.206 164.074 455.087 159.539 455.087 154.097C455.087 149.074 453.206 144.888 449.444 141.539C445.682 138.19 440.805 136.516 434.814 136.516C428.822 136.516 423.946 138.26 420.184 141.748C416.422 145.237 414.541 149.562 414.541 154.725C414.541 159.888 416.422 164.214 420.184 167.702Z" fill="#FAFAFA"/>
|
||||
<path d="M482.873 7.00195C496.804 7.00195 508.018 11.1745 516.516 19.5195C525.153 27.8646 529.472 40.2431 529.472 56.655V120.912H496.873V61.662C496.873 52.7606 494.923 46.1541 491.022 41.8425C487.122 37.3918 481.479 35.1665 474.096 35.1665C465.877 35.1665 459.329 37.7396 454.453 42.8857C449.577 47.8927 447.139 55.4032 447.139 65.4173V120.912H414.541V8.67096H445.677V21.8144C449.995 17.0856 455.359 13.4694 461.767 10.9658C468.175 8.32325 475.21 7.00195 482.873 7.00195Z" fill="#FAFAFA"/>
|
||||
<path d="M660.787 65.2087C660.787 65.6259 660.578 68.5467 660.16 73.971H575.111C576.644 80.9252 580.266 86.419 585.977 90.4524C591.689 94.4859 598.794 96.5026 607.292 96.5026C613.143 96.5026 618.298 95.6681 622.755 93.9991C627.353 92.191 631.602 89.4093 635.502 85.654L652.846 104.43C642.259 116.531 626.795 122.581 606.456 122.581C593.779 122.581 582.564 120.147 572.813 115.279C563.061 110.272 555.538 103.387 550.244 94.625C544.951 85.8627 542.304 75.9181 542.304 64.7914C542.304 53.8038 544.881 43.9288 550.035 35.1665C555.329 26.2651 562.504 19.3804 571.559 14.5125C580.753 9.50546 590.993 7.00195 602.277 7.00195C613.282 7.00195 623.243 9.36639 632.159 14.0952C641.075 18.8241 648.04 25.6392 653.055 34.5406C658.21 43.3029 660.787 53.5256 660.787 65.2087ZM602.486 31.6198C595.102 31.6198 588.903 33.7061 583.888 37.8786C578.873 42.0512 575.808 47.7536 574.693 54.986H630.069C628.955 47.8927 625.89 42.2598 620.875 38.0873C615.86 33.7757 609.73 31.6198 602.486 31.6198Z" fill="#FAFAFA"/>
|
||||
<path d="M792.037 8.67096L744.602 120.912H710.959L663.732 8.67096H697.376L728.512 85.0282L760.692 8.67096H792.037Z" fill="#FAFAFA"/>
|
||||
<path d="M912.403 65.2087C912.403 65.6259 912.194 68.5467 911.776 73.971H826.727C828.26 80.9252 831.882 86.419 837.593 90.4524C843.305 94.4859 850.41 96.5026 858.908 96.5026C864.759 96.5026 869.913 95.6681 874.371 93.9991C878.969 92.191 883.217 89.4093 887.118 85.654L904.462 104.43C893.875 116.531 878.411 122.581 858.072 122.581C845.395 122.581 834.18 120.147 824.429 115.279C814.677 110.272 807.154 103.387 801.86 94.625C796.566 85.8627 793.92 75.9181 793.92 64.7914C793.92 53.8038 796.497 43.9288 801.651 35.1665C806.945 26.2651 814.12 19.3804 823.175 14.5125C832.369 9.50546 842.609 7.00195 853.893 7.00195C864.898 7.00195 874.859 9.36639 883.775 14.0952C892.691 18.8241 899.656 25.6392 904.671 34.5406C909.826 43.3029 912.403 53.5256 912.403 65.2087ZM854.102 31.6198C846.718 31.6198 840.519 33.7061 835.504 37.8786C830.488 42.0512 827.424 47.7536 826.309 54.986H881.685C880.571 47.8927 877.506 42.2598 872.491 38.0873C867.475 33.7757 861.346 31.6198 854.102 31.6198Z" fill="#FAFAFA"/>
|
||||
<path d="M965.242 23.4834C969.143 18.0591 974.367 13.9562 980.914 11.1745C987.601 8.39279 995.263 7.00195 1003.9 7.00195V37.0441C1000.28 36.766 997.841 36.6269 996.587 36.6269C987.253 36.6269 979.939 39.2695 974.645 44.5547C969.352 49.7008 966.705 57.4895 966.705 67.9208V120.912H934.106V8.67096H965.242V23.4834Z" fill="#FAFAFA"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.9 KiB |
@@ -15,6 +15,14 @@ const navigation = [
|
||||
{ title: "Setup with Vue.js", href: "/docs/getting-started/vuejs" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Best Practices",
|
||||
links: [
|
||||
/* { title: "Feedback Box", href: "/docs/best-practices/feedback-box" }, */
|
||||
{ title: "Docs Feedback", href: "/docs/best-practices/docs-feedback" },
|
||||
/* { title: "In-app Interview Prompt", href: "/docs/best-practices/interview-prompt" }, */
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Attributes",
|
||||
links: [
|
||||
@@ -24,11 +32,11 @@ const navigation = [
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Events",
|
||||
title: "Actions",
|
||||
links: [
|
||||
{ title: "Why Events?", href: "/docs/events/why" },
|
||||
{ title: "No-Code Events", href: "/docs/events/no-code" },
|
||||
{ title: "Code Events", href: "/docs/events/code" },
|
||||
{ title: "Why Actions?", href: "/docs/actions/why" },
|
||||
{ title: "No-Code Actions", href: "/docs/actions/no-code" },
|
||||
{ title: "Code Actions", href: "/docs/actions/code" },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -66,6 +66,22 @@ const nextConfig = {
|
||||
destination: "/docs",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: "/docs/events/why",
|
||||
destination: "/docs/actions/why",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: "/docs/events/code",
|
||||
destination: "/docs/actions/code",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: "/docs/events/code",
|
||||
destination: "/docs/actions/code",
|
||||
permanent: true,
|
||||
},
|
||||
|
||||
{
|
||||
source: "/pmf",
|
||||
destination: "/",
|
||||
|
||||
25
apps/formbricks-com/pages/docs/actions/code/index.mdx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Code Actions",
|
||||
description:
|
||||
"Integrate code actions in Formbricks using formbricks.track() to trigger surveys based on user actions, like button clicks, for precise insights. All open-source.",
|
||||
};
|
||||
|
||||
Actions can also be set in the code base. You can fire an action using `formbricks.track()`
|
||||
|
||||
```javascript
|
||||
formbricks.track("Action Name");
|
||||
```
|
||||
|
||||
Here is an example of how to fire an action when a user clicks a button:
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
formbricks.track("Button Clicked");
|
||||
};
|
||||
|
||||
return <button onClick={handleClick}>Click Me</button>;
|
||||
```
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
30
apps/formbricks-com/pages/docs/actions/no-code/index.mdx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "No-Code Actions",
|
||||
description:
|
||||
"Utilize Formbricks' No-Code Actions like Page URL, innerText, and CSS Selector for easy survey triggers and enhanced user insights.",
|
||||
};
|
||||
|
||||
No-Code actions can be set up within Formbricks with just a few clicks. There are three types of No-Code actions:
|
||||
|
||||
## Page URL Action
|
||||
|
||||
The page URL action is triggered, when a user visits a specific page in your application. There are several match conditions:
|
||||
|
||||
- `exactMatch`: The URL should exactly match the provided string.
|
||||
- `contains`: The URL should contain the specified string as a substring.
|
||||
- `startsWith`: The URL should start with the specified string.
|
||||
- `endsWith`: The URL should end with the specified string.
|
||||
- `notMatch`: The URL should not match the specified condition.
|
||||
- `notContains`: The URL should not contain the specified string as a substring.
|
||||
|
||||
## innerText Action
|
||||
|
||||
The innerText action checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button. Display a survey on any button click!
|
||||
|
||||
## CSS Selector Action
|
||||
|
||||
The CSS Selector action checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website. Display a survey on any element click!
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
23
apps/formbricks-com/pages/docs/actions/why/index.mdx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "What are actions and why are they useful?",
|
||||
description:
|
||||
"Actions in Formbricks enable targeted survey displays during specific user journey moments. Enhance user segmentation by tracking actions for granular surveying.",
|
||||
};
|
||||
|
||||
You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need actions.
|
||||
|
||||
## What are actions?
|
||||
|
||||
Actions are a little notification sent from your application to Formbricks. You decide which actions are sent either in your [Code](/docs/actions/code) or by setting up a [No-Code](/docs/actions/no-code) action within Formbricks.
|
||||
|
||||
## How do actions work?
|
||||
|
||||
When a predefined action happens in your app, the Formbricks widget notices. This action can then trigger a survey to be shown to the user and is stored in the database.
|
||||
|
||||
## Why are actions useful?
|
||||
|
||||
Actions help you to display your surveys at the right time. Later on, you will be able to segment your users based on the actions they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
|
||||
export const meta = {
|
||||
title: "Custom Survey",
|
||||
};
|
||||
|
||||
<Callout title="Visual Form Builder in progress" type="note">
|
||||
We're working on a visual form builder so that you can create custom forms within Formbricks. Sign up now to
|
||||
stay in the loop!
|
||||
</Callout>
|
||||
|
||||
## Purpose
|
||||
|
||||
Build custom forms without the backend: Use Formbricks to gather and analyze form submissions. Pipe the data where you need it.
|
||||
|
||||
## Formbricks Approach
|
||||
|
||||
- Custom forms allow 100% customizability (duh!)
|
||||
- Use Formbricks backend as endpoint
|
||||
- Use Formbricks Data Pipelines to forward data where you need it.
|
||||
|
||||
## Creating and updating a submission via our API
|
||||
|
||||
Create your frontend the way you want it and send the data to our API. For this we provide two endpoints, one for creating a new submission and one for updating an existing submission.
|
||||
|
||||
You can send all the data at once to our endpoint to create a submission or if you want to build a multipage survey you can send the data for each page separately. Then you use the first API call to create a new submission and the second API call to update the submission with the data from the next page.
|
||||
|
||||
Please refer to [Create Submission](/docs/api/create-submission) and [Update Submission](/docs/api/update-submission) for more information.
|
||||
|
||||
## API docs
|
||||
|
||||
To fetch data from the API (e.g. submissions or forms) your need an API key. Please refer to our [API documentation](/docs/api/setup).
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,384 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
import Image from "next/image";
|
||||
|
||||
import DocsFeedback from "@/components/docs/DocsFeedback";
|
||||
import AddAction from "./add-action.png";
|
||||
import ChangeId from "./change-id.png";
|
||||
import DocsNavi from "./docs-navi.png";
|
||||
import DocsTemplate from "./docs-template.png";
|
||||
import SelectNonevent from "./select-nonevent.png";
|
||||
import SwitchToDev from "./switch-to-dev.png";
|
||||
import WhenToAsk from "./when-to-ask.png";
|
||||
import CopyIds from "./copy-ids.png";
|
||||
|
||||
export const meta = {
|
||||
title: "Docs Feedback",
|
||||
};
|
||||
|
||||
Docs Feedback allows you to measure how clear your documentation is.
|
||||
|
||||
## Purpose
|
||||
|
||||
Unlike yourself, your users don't spend 5-7 days per week thinking about your product. To fight the "Curse of Knowledge" you have to measure how clear your docs are.
|
||||
|
||||
## Preview
|
||||
|
||||
<DocsFeedback />
|
||||
|
||||
## Installation
|
||||
|
||||
To get this running, you'll need a bit of time. Here are the steps we're going through:
|
||||
|
||||
1. Set up Formbricks Cloud
|
||||
2. Build the frontend
|
||||
3. Connect to API
|
||||
4. Test
|
||||
|
||||
### 1. Setting up Formbricks Cloud
|
||||
|
||||
1. To get started, create an account for the [Formbricks Cloud](https://app.formbricks.com/auth/signup).
|
||||
|
||||
2. In the Menu (top right) you see that you can switch between a “Development” and a “Production” environment. These are two separate environments so your test data doesn’t mess up the insights from prod. Switch to “Development”:
|
||||
|
||||
<Image src={SwitchToDev} alt="switch to dev environment" quality="100" className="rounded" />
|
||||
|
||||
3. Then, create a survey using the template “Docs Feedback”:
|
||||
|
||||
<Image src={DocsTemplate} alt="select docs template" quality="100" className="rounded" />
|
||||
|
||||
4. Change the Internal Question ID of the first question to **“isHelpful”** to make your life easier 😉
|
||||
|
||||
<Image src={ChangeId} alt="switch to dev environment" quality="100" className="rounded" />
|
||||
|
||||
5. In the same way, you can change the Internal Question ID of the _Please elaborate_ question to **“additionalFeedback”** and the one of the _Page URL_ question to **“pageUrl”**.
|
||||
|
||||
<Callout title="Answers need to be identical" type="note">
|
||||
If you want different answers than “Yes 👍” and “No 👎” you need update the choices accordingly. They have
|
||||
to be identical to the frontend we're building in the next step.
|
||||
</Callout>
|
||||
|
||||
6. Click on “Continue to Audience” or select the audience tab manually. Scroll down to “When to ask” and create a new Action:
|
||||
|
||||
<Image src={WhenToAsk} alt="set up when to ask card" quality="100" className="rounded" />
|
||||
|
||||
7. Our goal is to create an event that never fires. This is a bit nonsensical because it is a workaround. Stick with me 😃 Fill the action out like on the screenshot:
|
||||
|
||||
<Image src={AddAction} alt="add action" quality="100" className="rounded" />
|
||||
|
||||
8. Select the Non-Event in the dropdown. Now you see that the “Publish survey” button is active. Publish your survey 🤝
|
||||
|
||||
<Image src={SelectNonevent} alt="select nonevent" quality="100" className="rounded" />
|
||||
|
||||
**You’re all setup in Formbricks Cloud for now 👍**
|
||||
|
||||
### 2. Build the frontend
|
||||
|
||||
<Callout title="Your frontend might work differently" type="note">
|
||||
Your frontend likely looks and works differently. This is an example specific to our tech stack. We want to
|
||||
illustrate what you should consider building yours 😊
|
||||
</Callout>
|
||||
|
||||
Before we start, lets talk about the widget. It works like this:
|
||||
|
||||
- Once the user selects yes/no, a partial response is created in Formbricks. It includes the feedback and the current page url.
|
||||
- Then the user is presented with an additional open text field to further explain their choice. Once it's submitted, the previous response is updated with the additional feedback.
|
||||
|
||||
This allows us to capture and analyze partial feedback where the user is not willing to provide additional information.
|
||||
|
||||
**Let's do this 👇**
|
||||
|
||||
1. Open the code editor where you handle your docs page.
|
||||
|
||||
2. Likely, you have a template file or similar which renders the navigation at the bottom of the page:
|
||||
|
||||
<Image src={DocsNavi} alt="doc navigation" quality="100" className="rounded" />
|
||||
|
||||
Locate that file. We are using the [Tailwind Template “Syntax”](https://tailwindui.com/templates/syntax) for our docs. Here is our [Layout.tsx](https://github.com/formbricks/formbricks/blob/main/apps/formbricks-com/components/docs/Layout.tsx) file.
|
||||
|
||||
3. Write the frontend code for the widget. Here is the full component (we break it down right below):
|
||||
|
||||
```tsx
|
||||
import { useState } from "react";
|
||||
import { handleFeedbackSubmit, updateFeedback } from "../../lib/handleFeedbackSubmit";
|
||||
import { Popover, PopoverTrigger, PopoverContent, Button } from "@formbricks/ui";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function DocsFeedback() {
|
||||
const router = useRouter();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [sharedFeedback, setSharedFeedback] = useState(false);
|
||||
const [responseId, setResponseId] = useState(null);
|
||||
const [freeText, setFreeText] = useState("");
|
||||
|
||||
if (
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID ||
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_API_HOST ||
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-6 inline-flex cursor-default items-center rounded-md border border-slate-200 bg-white p-4 text-slate-800 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300">
|
||||
{!sharedFeedback ? (
|
||||
<div>
|
||||
Was this page helpful?
|
||||
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
||||
<div className="ml-4 inline-flex space-x-3">
|
||||
{["Yes 👍", " No 👎"].map((option) => (
|
||||
<PopoverTrigger
|
||||
className="rounded border border-slate-200 bg-slate-50 px-4 py-2 text-slate-900 hover:bg-slate-100 hover:text-slate-600 focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 dark:hover:text-slate-300"
|
||||
onClick={async () => {
|
||||
const id = await handleFeedbackSubmit(option, router.asPath);
|
||||
setResponseId(id);
|
||||
}}>
|
||||
{option}
|
||||
</PopoverTrigger>
|
||||
))}
|
||||
</div>
|
||||
<PopoverContent className="border-slate-300 bg-white dark:border-slate-500 dark:bg-slate-700">
|
||||
<form>
|
||||
<textarea
|
||||
value={freeText}
|
||||
onChange={(e) => setFreeText(e.target.value)}
|
||||
placeholder="Please explain why..."
|
||||
className="focus:border-brand-dark focus:ring-brand-dark mb-2 w-full rounded-md bg-white text-sm text-slate-900 dark:bg-slate-600 dark:text-slate-200 dark:placeholder:text-slate-200"
|
||||
/>
|
||||
<div className="text-right">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
updateFeedback(freeText, responseId);
|
||||
setIsOpen(false);
|
||||
setFreeText("");
|
||||
setSharedFeedback(true);
|
||||
}}>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
) : (
|
||||
<div>Thanks a lot, boss! 🤝</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**Let’s break it down!**
|
||||
|
||||
Setting the local states and getting the current URL:
|
||||
|
||||
```tsx
|
||||
const router = useRouter(); // to get the URL of the current docs page
|
||||
const [isOpen, setIsOpen] = useState(false); // to close Popover after
|
||||
const [sharedFeedback, setSharedFeedback] = useState(false); // to display Thank You message
|
||||
const [responseId, setResponseId] = useState(null); // to store responseID (will explain more)
|
||||
const [freeText, setFreeText] = useState(""); // to locally store the additional info provided by user
|
||||
```
|
||||
|
||||
Disabling feedback if config environment variables are not set properly:
|
||||
|
||||
```tsx
|
||||
// Disables feedback if key info like survey ID, API Host, or Formbricks environment ID are missing
|
||||
|
||||
if (
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID ||
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_API_HOST ||
|
||||
!process.env.NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
The actual frontend (read comments):
|
||||
|
||||
```tsx
|
||||
return (
|
||||
<div className="mt-6 inline-flex cursor-default items-center rounded-md border border-slate-200 bg-white p-4 text-slate-800 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300">
|
||||
{!sharedFeedback ? ( // displays Feedback buttons or Thank You message
|
||||
<div>
|
||||
Was this page helpful?
|
||||
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
||||
<div className="ml-4 inline-flex space-x-3">
|
||||
{["Yes 👍", " No 👎"].map((option) => ( // Popup Trigger is a button as well. This is a workaround to open the same form but send a different response to the API
|
||||
<PopoverTrigger
|
||||
className="rounded border border-slate-200 bg-slate-50 px-4 py-2 text-slate-900 hover:bg-slate-100 hover:text-slate-600 focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-slate-700 dark:bg-slate-700 dark:text-slate-300 dark:hover:bg-slate-600 dark:hover:text-slate-300"
|
||||
onClick={async () => {
|
||||
const id = await handleFeedbackSubmit(option, router.asPath); // handleFeedbackSubmit sends the Yes / No choice as well as the current URL to Formbricks and returns the responseId
|
||||
setResponseId(id); // add responseId to local state so we can use it if user decides to add more feedback in free text field
|
||||
}}>
|
||||
{option} // "Yes 👍" or "No 👎" - they have to be identical with the choices in the survey on app.formbricks.com for it to work (!)
|
||||
</PopoverTrigger>
|
||||
))}
|
||||
</div>
|
||||
<PopoverContent className="border-slate-300 bg-white dark:border-slate-500 dark:bg-slate-700">
|
||||
<form> // Form to handle additional feedback by user
|
||||
<textarea
|
||||
value={freeText}
|
||||
onChange={(e) => setFreeText(e.target.value)}
|
||||
placeholder="Please explain why..."
|
||||
className="focus:border-brand-dark focus:ring-brand-dark mb-2 w-full rounded-md bg-white text-sm text-slate-900 dark:bg-slate-600 dark:text-slate-200 dark:placeholder:text-slate-200"
|
||||
/>
|
||||
<div className="text-right">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
onClick={(e) => {
|
||||
e.preventDefault(); // prevent page from reloading (default HTML behaviour)
|
||||
updateFeedback(freeText, responseId); // update initial Yes / No response with free text feedback
|
||||
setIsOpen(false); // close Popover
|
||||
setFreeText(""); // remove feedback from free text field local state
|
||||
setSharedFeedback(true); // display Thank You message
|
||||
}}>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
) : (
|
||||
<div>Thanks a lot, boss! 🤝</div> // Thank You message
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Connecting to the Formbricks API
|
||||
|
||||
The last step is to hook up your sparkling new frontend to the Formbricks API. To do so, we followed the “[Create Response](https://formbricks.com/docs/api/create-response)” and “[Update Response](https://formbricks.com/docs/api/update-response)” pages in our docs.
|
||||
|
||||
Here is the code for the `handleFeedbackSubmit` function with comments:
|
||||
|
||||
```tsx
|
||||
export const handleFeedbackSubmit = async (YesNo, pageUrl) => {
|
||||
const response_data = {
|
||||
data: {
|
||||
isHelpful: YesNo, // the "Yes 👍" or "No 👎" response. Remember: They have to be identical with the choices in the survey on app.formbricks.com for it to work.
|
||||
pageUrl: pageUrl, // So you know which page the user gives feedback about.
|
||||
},
|
||||
};
|
||||
|
||||
const payload = {
|
||||
response: response_data,
|
||||
surveyId: process.env.NEXT_PUBLIC_FORMBRICKS_COM_DOCS_FEEDBACK_SURVEY_ID, // For testing, replace this with the survey ID of your survey (more info below)
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_FORMBRICKS_COM_API_HOST}/api/v1/client/environments/${process.env.NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID}/responses`, // For testing, replace this with the API host and environemnt ID of your Development environment on app.formbricks.com
|
||||
};
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
);
|
||||
|
||||
if (res.ok) {
|
||||
const responseJson = await res.json();
|
||||
return responseJson.id; // Returns the response ID
|
||||
} else {
|
||||
console.error("Error submitting form");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error submitting form:", error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
And this is the `updateFeedback` function with comments:
|
||||
|
||||
```tsx
|
||||
export const updateFeedback = async (freeText, responseId) => {
|
||||
if (!responseId) {
|
||||
console.error("No response ID available"); // If there is not response ID, no response can be updated.
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
response: {
|
||||
data: {
|
||||
additionalInfo: freeText,
|
||||
},
|
||||
finished: true, // Lets Formbricks calculate Completion Rate
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_FORMBRICKS_COM_API_HOST}/api/v1/client/environments/${process.env.NEXT_PUBLIC_FORMBRICKS_COM_ENVIRONMENT_ID}/responses/${responseId}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
}
|
||||
);
|
||||
|
||||
if (!res.ok) {
|
||||
console.error("Error updating response");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error updating response:", error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
That’s almost it! 🤸
|
||||
|
||||
## 4. Setting it up for testing
|
||||
|
||||
Before you roll it out in production, you want to test it. To do so, you need two things:
|
||||
|
||||
1. Environment ID (1) of the development environment on app.formbricks.com
|
||||
2. Survey ID (2) of your test survey
|
||||
|
||||
When you are on the survey detail page, you’ll find both of them in the URL:
|
||||
|
||||
<Image src={CopyIds} alt="copy IDs" quality="100" className="rounded" />
|
||||
|
||||
Now, you have to replace the IDs and the API host accordingly in your `handleFeedbackSubmit`:
|
||||
|
||||
```tsx
|
||||
const payload = {
|
||||
response: response_data,
|
||||
surveyId: clgwfv4a7002el50ihyuss38x, // This is an example, replace with yours
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await fetch(
|
||||
// Note that we also updated the API host to 'https://app.formbricks.com/'
|
||||
`https:app.formbricks.com/api/v1/client/environments/clgwcwp4z000lpf0hur7uxbuv/responses`,
|
||||
};
|
||||
```
|
||||
|
||||
And lastly, in the `updateFeedback` function
|
||||
|
||||
```tsx
|
||||
try {
|
||||
const res = await fetch(
|
||||
// Note that we also updated the API host to 'https://app.formbricks.com/'
|
||||
`https:app.formbricks.com/api/v1/client/environments/clgwcwp4z000lpf0hur7uxbuv/responses/${responseId}`, // Note that we also updated the API host to 'https://app.formbricks.com/'
|
||||
}
|
||||
```
|
||||
|
||||
### You’re good to go! 🎉
|
||||
|
||||
Something doesn’t work? Check your browser console for the error.
|
||||
|
||||
Can’t figure it out? [Join our Discord!](https://formbricks.com/discord)
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 10 KiB |
@@ -3,14 +3,13 @@ import { Fence } from "@/components/shared/Fence";
|
||||
import Link from "next/link";
|
||||
import NewFB from "@/images/docs/create-feedback-box.png";
|
||||
import FBID from "@/images/docs/fb-id.png";
|
||||
import ResponsiveEmbed from "react-responsive-embed";
|
||||
import Image from "next/image";
|
||||
|
||||
export const meta = {
|
||||
title: "Feedback Box",
|
||||
};
|
||||
|
||||
The Feedback Box is an easy way to gather feedback from users in your app.
|
||||
The Feedback Box gives your user a direct channel to share their feedback and feel heard.
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -19,31 +18,20 @@ Allow users to share feedback with 2 clicks. A low friction way to gather feedba
|
||||
## Formbricks Approach
|
||||
|
||||
- Make it **easy**: 2 clicks to share feedback
|
||||
- Keep it **personal**: Founder faces
|
||||
- **Pre-sort** feedback:
|
||||
- Bug → Pipe into Bug channel for devs
|
||||
- Feedback → Pipe into Feedback channel for PM’s
|
||||
- Appreciation → Pipe into General channel for team spirit & testimonials
|
||||
|
||||
## Preview
|
||||
|
||||
<div className="max-w-md">
|
||||
<ResponsiveEmbed
|
||||
src="/docs/wrappers/slide-out/demo"
|
||||
allowFullScreen
|
||||
className="rounded-lg border-2 border-slate-200"
|
||||
ratio="8:10"
|
||||
/>
|
||||
</div>
|
||||
|
||||
## Installation
|
||||
|
||||
To add the Feedback Box to your app, you need to perform these steps:
|
||||
|
||||
1. Create new Feedback Box at app.formbricks.com
|
||||
2. Embed JS snippet in `<head>`
|
||||
3. Configure
|
||||
4. Render in-app
|
||||
2. Setup Feedback Box with template
|
||||
3. Use NPM to install or embed JS snippet in `<head>`
|
||||
4. Test
|
||||
|
||||
### 1. Create new Feedback Box
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
|
||||
export const meta = {
|
||||
title: "Onboarding Segmentation",
|
||||
};
|
||||
|
||||
<Callout title="Closed Beta" type="note">
|
||||
Onboarding Segmentation is only available in closed beta. Want to become a design partner? Reach out at
|
||||
hola@formbricks.com
|
||||
</Callout>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
import { Callout } from "@/components/shared/Callout";
|
||||
|
||||
export const meta = {
|
||||
title: "Waitlist Survey",
|
||||
};
|
||||
|
||||
<Callout title="Closed Beta" type="note">
|
||||
The Waitlist Survey is only available in closed beta. Want to become a design partner? Reach out at
|
||||
hola@formbricks.com
|
||||
</Callout>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
import { Fence } from "@/components/shared/Fence";
|
||||
|
||||
export const meta = {
|
||||
title: "What are Best Practices?",
|
||||
};
|
||||
|
||||
Best Practices are end-to-end productized methods for managing product. They are designed to make **product-led growth easier**.
|
||||
|
||||
A Best Practice consists of two parts:
|
||||
|
||||
- A set of **survey questions** / method to determine questions
|
||||
- A **specifically designed dashboard** to interact with the qualitative data
|
||||
|
||||
## Current Best Practices
|
||||
|
||||
| Name | Purpose | Status |
|
||||
| ------------------------- | ------------------------------------------------------------- | ----------- |
|
||||
| Feedback Box | Gather feedback from users in your app as easily as possible. | Public Beta |
|
||||
| Product-Market Fit Survey | Continuously masure PMF score to be able to optimize it | Public Beta |
|
||||
| Onboarding Segmentation | Segment new users as they onboard your service | Closed Beta |
|
||||
| Waitlist survey | Gather key information about your user base pre-product | Closed Beta |
|
||||
| In-app Interview Prompt | Invite selected users in-app to book an interview | Up next |
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "Code Events",
|
||||
description:
|
||||
"Integrate code events in Formbricks using formbricks.track() to trigger surveys based on user actions, like button clicks, for precise insights. All open-source.",
|
||||
};
|
||||
|
||||
Events can also be set in the code base. You can fire an event using `formbricks.track()`
|
||||
|
||||
```javascript
|
||||
formbricks.track("Event Name");
|
||||
```
|
||||
|
||||
Here is an example of how to fire an event when a user clicks a button:
|
||||
|
||||
```javascript
|
||||
const handleClick = () => {
|
||||
formbricks.track("Button Clicked");
|
||||
};
|
||||
|
||||
return <button onClick={handleClick}>Click Me</button>;
|
||||
```
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "No-Code Events",
|
||||
description:
|
||||
"Utilize Formbricks' No-Code Events like Page URL, innerText, and CSS Selector for easy survey triggers and enhanced user insights.",
|
||||
};
|
||||
|
||||
No-Code events can be set up within Formbricks with just a few clicks. There are three types of No-Code events:
|
||||
|
||||
## Page URL Event
|
||||
|
||||
The page URL event is triggered, when a user visits a specific page in your application. There are several match conditions:
|
||||
|
||||
- `exactMatch`: The URL should exactly match the provided string.
|
||||
- `contains`: The URL should contain the specified string as a substring.
|
||||
- `startsWith`: The URL should start with the specified string.
|
||||
- `endsWith`: The URL should end with the specified string.
|
||||
- `notMatch`: The URL should not match the specified condition.
|
||||
- `notContains`: The URL should not contain the specified string as a substring.
|
||||
|
||||
## innerText Event
|
||||
|
||||
The innerText event checks if the `innerText` of a clicked HTML element matches a specific text, e.g. the label of a button. Display a survey on any button click!
|
||||
|
||||
## CSS Selector Event
|
||||
|
||||
The CSS Selector event checks if the provided CSS selector matches the selector of a clicked HTML element. The CSS selector can be a class, id or any other CSS selector within your website. Display a survey on any element click!
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Layout } from "@/components/docs/Layout";
|
||||
|
||||
export const meta = {
|
||||
title: "What are events and why are they useful?",
|
||||
description:
|
||||
"Events in Formbricks enable targeted survey displays during specific user journey moments. Enhance user segmentation by tracking events for granular surveying.",
|
||||
};
|
||||
|
||||
You want to understand what your users think and feel during specific moments in the user journey. To be able to ask at exactly the right point in time, you need events.
|
||||
|
||||
## What are events?
|
||||
|
||||
Events are a little notification sent from your application to Formbricks. You decide which events are sent either in your [Code](/docs/events/code) or by setting up a [No-Code](/docs/events/no-code) event within Formbricks.
|
||||
|
||||
## How do events work?
|
||||
|
||||
When a predefined event happens in your app, the Formbricks widget notices. This event can then trigger a survey to be shown to the user and is stored in the database.
|
||||
|
||||
## Why are events useful?
|
||||
|
||||
Events help you to display your surveys at the right time. Later on, you will be able to segment your users based on the events they have triggered in the past. This way, you can create much more granular user segments, e.g. only target users that already have used a specific feature.
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>;
|
||||