{"id":15397777,"url":"https://github.com/devcrossnet/quaire","last_synced_at":"2025-04-16T01:08:46.257Z","repository":{"id":143803936,"uuid":"373632602","full_name":"devCrossNet/quaire","owner":"devCrossNet","description":"a framework-agnostic library to create user-flows, surveys, and questionnaires","archived":false,"fork":false,"pushed_at":"2021-09-18T15:44:36.000Z","size":944,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-16T01:05:16.105Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devCrossNet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-03T20:27:35.000Z","updated_at":"2023-12-22T18:14:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"f6bcb1c4-06d4-46fe-bca6-c97b8a6db248","html_url":"https://github.com/devCrossNet/quaire","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"f66f23ac39d2f3cc22caee183b142f2d8a5884c2"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devCrossNet%2Fquaire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devCrossNet%2Fquaire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devCrossNet%2Fquaire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devCrossNet%2Fquaire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devCrossNet","download_url":"https://codeload.github.com/devCrossNet/quaire/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249178212,"owners_count":21225349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T15:39:23.662Z","updated_at":"2025-04-16T01:08:46.231Z","avatar_url":"https://github.com/devCrossNet.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# quaire\n\na framework-agnostic library to create user-flows, surveys, and questionnaires\n\n# What type of application can I build with quaire?\n\nThe library was already used for\n\n- Call center software (call scripts)\n- Surveys\n- Briefings\n- Games\n- Questionnaires\n\n# Why the name?\n\nBecause I needed one and `Questionnaire` is terrible to type. Let me know if you have a better one!\n\n# What use-case does it try to solve?\n\nI have to implement more and more features that behave like questionnaires or surveys.\nOver the years I tried a couple of things to make it easier for me to implement those features.\n\nOf course, the first approach I tried was to implement a static user flow, for example:\n\n- present first question on first page\n- user selects option a\n- navigate to the next question\n- etc.\n\nThat was ok as long as I didn't have to change the flow but when I had to change the flow,\nI found myself changing big parts of the implementation.\n\nI also tried to use finite state machines,\nbut I ended up with spaghetti state machines most of the time\ndue to regular changes in the user-flow (re-arranging questions, adding questions, skip questions, etc.)\n\nThe solution I found to work best for me was a concept of game-development called decision-tree.\nThat way the whole user-flow is based on a static data structure that can be changed without the need of changing\nthe view or the behaviour. This pattern provides a nice separation of:\n\n- data\n- behaviour\n- presentation\n\n# Features?\n\n- Framework-agnostic\n- View independent\n- [Linear user-flow](https://github.com/devCrossNet/quaire/tree/main/examples/linear-flow)\n- [Branched/merged user-flow](https://github.com/devCrossNet/quaire/tree/main/examples/branched-and-merged-flow)\n- [Loops](https://github.com/devCrossNet/quaire/tree/main/examples/linear-flow-with-loop)\n- [Dependencies between questions and validation](https://github.com/devCrossNet/quaire/tree/main/examples/dependencies-between-questions)\n- [Re-storing state of the questionnaire from the selected answers](https://github.com/devCrossNet/quaire/blob/main/examples/restore-state.spec.ts)\n- Navigation\n\n# How does it work?\n\n## Installation\n\n```shell\nnpm i --save quaire\n```\n\n## Define quaire data\n\nFirst you need to define the data (decision tree) based on the\n[QuaireItem interface](https://github.com/devCrossNet/quaire/blob/main/src/interfaces.ts#L43). This can be static\ndata in a JS/TS file, a JSON file that you load on demand\nor a dynamic JSON from a CMS or backend API.\n\nThe structure for questions looks as follows:\n\n```js\nimport { QuaireComponentType, QuaireItem, QuaireNavigationItem } from 'quaire';\n\nexport const items: QuaireItem[] = [\n  {\n    id: 1,\n    resultProperty: 'foo', // property that is used to save the answer\n    navigationItemId: 1, // association with the navigation entry (optional)\n    dependsOnResultProperties: [], // dependencies on answers from former questions, based on the result property - not question ID\n    componentType: QuaireComponentType.SINGLE_SELECT, // component type as indication for custom presentation logic\n    question: 'Question 1',\n    description: 'Description 1',\n    required: true,\n    selectOptions: [], // options for select components (optional)\n    rangeOption: {}, // option for range components (optional)\n    inputOption: {}, // option for input components (optional)\n    defaultValue: {}, // default value for any kind of component (optional)\n    nextItemId: {}, // id of the follow up question (optional), usually you want to define this in selectOptions, rangeOption or inputOption\n  },\n  // ...\n];\n```\n\nThe structure for the navigation looks a follows:\n\n```js\nexport const navigationItems: QuaireNavigationItem[] = [\n  {\n    id: 1,\n    parentId: null, // has no parent\n    name: 'Category 1',\n  },\n  {\n    id: 2,\n    parentId: 1, // has a parent (works only for one level)\n    name: 'Subcategory 1',\n  },\n  {\n    id: 3,\n    parentId: null,\n    name: 'Category 2',\n  },\n];\n```\n\n## Use quaire behaviour\n\nTo use the default behavior you need to initialize `Quaire` with the data you\ndefined in the former step.\n\n```js\nimport { Quaire } from 'quaire';\n\nconst q = new Quaire({ items, navigationItems }); // (optional) you can pass an existing result to restore the questionnaire\n```\n\nNext you can get the first active Question and display it in any way you want\n\n```js\nlet activeQuestion = q.getActiveQuestion(); // first question\nlet navigation = q.getNavigation(); // initial navigation\nlet result = q.getResult(); // initial result\n\n// display activeQuestion.question and the related component presentation logic\n// Vue.js pseudo code example\n\u003ctemplate\u003e\n    \u003cdiv\u003e\n        \u003ctemplate v-if=\"activeQuestion.componentType === 'SINGLE_SELECT'\"\u003e\n            {{ activeQuestion.question }}\n            // loop through activeQuestion.selectOptions, etc.\n        \u003ctemplate\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n\nAfter the user selected an answer you can save the answer and get the next question.\nIt's also a good idea to update the navigation and result\n\n```js\nonSubmit(value: any) {\n    q.saveAnswer(value);\n    activeQuestion = q.getActiveQuestion(); // follow up question\n    navigation = q.getNavigation(); // update navigation\n    result = q.getResult(); // update result\n\n    // ...\n}\n```\n\nYou need to identify the end of the user-flow on your own.\nOne way to do it is via the question ID or you create some logic around\nthe result object of the Questionnaire.\n\n```js\nonSubmit(value: any) {\n    // ...\n    const isValid = q.isValid();\n\n    // check if the questionnaire is valid\n    if(!isValid) {\n        return;\n    }\n\n    // via ID\n    if(activeQuestion.id === 3) {\n        // persist result to the backend, redirect to another page,\n        // whatever you want after the questionnaire is filled out\n    }\n\n    // via result\n    if(result.foo \u0026\u0026 result.bar \u0026\u0026 result.baz) {\n        // persist result to the backend, redirect to another page,\n        // whatever you want after the questionnaire is filled out\n    }\n}\n```\n\n# Extend quaire\n\n- [Custom component types](https://github.com/devCrossNet/quaire/tree/main/examples/custom-component-types)\n- [Extending data definition](https://github.com/devCrossNet/quaire/tree/main/examples/extending-data-definition)\n\n# Examples\n\n- [Linear flow](https://github.com/devCrossNet/quaire/tree/main/examples/linear-flow)\n- [Linear flow with a loop](https://github.com/devCrossNet/quaire/tree/main/examples/linear-flow-with-loop)\n- [Linear flow with option question](https://github.com/devCrossNet/quaire/tree/main/examples/linear-flow-skip-question)\n- [Branched flow that merges back into one](https://github.com/devCrossNet/quaire/tree/main/examples/branched-and-merged-flow)\n- [Dependencies between questions and validation](https://github.com/devCrossNet/quaire/tree/main/examples/dependencies-between-questions)\n- [Re-storing state of the questionnaire from the selected answers](https://github.com/devCrossNet/quaire/tree/main/examples/restore-state.spec.ts)\n\n# Contribute\n\nContributions are always welcome! Please read the [contribution guidelines](https://github.com/devCrossNet/quaire/blob/master/.github/CONTRIBUTING.md) first.\n\n# Contact\n\n- [Discord](https://discord.gg/59x5cg2)\n- [Twitter](https://twitter.com/_jwerner_)\n\n# License\n\n[MIT](http://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevcrossnet%2Fquaire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevcrossnet%2Fquaire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevcrossnet%2Fquaire/lists"}