enciv / civil-pursuit Goto Github PK
View Code? Open in Web Editor NEWLicense: Other
License: Other
Render one point for review in the review step.
<ReviewPoint className={}
read=false
rank=""
subject=""
description=""
leftPointList=[]
rightPointList=[]
onDone=()=>{}
/>
<GroupingStep style={} className=""
shared={ // this is an object with data that can be manipulate (mutated) by the steps
pointList=[{}] // this is an array of pointObj
groupedPointList=[{}] // if this prop doesn't exist create it, deepClone of startingPointList then adjusted based on user interaction
}
onDone=()=>{valid: ready, value: groupedPointList} // function to call when the ready state changes - after first render this needs to be called with true, but changes to false when the user is in the middle of a grouping
/>
Storybook
Stretch Goal
After upgrading to [email protected] the "if you logout now" popup is shown at the bottom, when it should be invisible.
Do get here, run the dev server and go to http://localhost:3011/item/pvote and then fill in your demographic info, and use skip at the login/join step.
Currently, master is on an older version of react-jss so you will need to npm install [email protected]
to get to this.
<HowDoYouFeel onDone=()=>{}/>
The API call information will be provided later, for now just render the component.
<RankStep
shared: {
pointList=[] // could be a pointComponent or a pointGroup
rankList=[] // {id, rank} where id is the id of the point and rank the rank - Most, Least, Neutral
}
onDone=()=>({})
/>
onDone({valid: doneCount===totalCount, value: doneCount / totalCount})
<PointInput style={} className=""
question=""
why=""
shared={
startingPointList=[]
whyMostList=[]
}
/>
TBD
This issue still needs some definition.
Get this working on node version 18
We need to add a stage in the discussion process where the user is asked to group similar items. This would be right after the users enters their own ideas, and before the users sorts the most important. From the unpoll project there is CardListGrouper.
Ideally CardListGrouper could be turned into a component that is used both projects, and styled differently depending on the project.
Before the grouper step can be applied, we also need to update the codebase to support the concept that an Item could be an Item or a [ListOfItems]
That will be issue #8 and that needs to be done first.
This is like the Item component, but based on the new UI and simpler.
See the React component guidelines and notes for the basic guidelines.
Properties:
In figma in developers mode, you can click on an instance of the point and see that it has a few paramaters. These are clues to the vState but something line onHover is not a vState it's just the hover case. The trash refers to if the remove button is present. We could do that as a property, or we could just make it a child - to be determined. The 'size' property shown here should be ignored. In React we will be basing everything on the fontsize (rem) (see the guidelines).
First Name | 45, UT
should be the <DemInfo {...otherProps} />
component.const {subject, description, vState, children, styles, classname, ...otherProps} = props
A user reported:
I was able to login and I filled out the first page, but for some reason, the "next" button wasn't working so I couldn't continue forward.
The issue was that they had not entered title/summery for each answer.
To duplicate this, start here: https://civilpursuit.herokuapp.com/item/pvote
Then you will be at the input page
We are converting this from Storybook version 4 to version 7. The format for stories and tests have changed. The first 2 stories have been converted, the rest are commented out.
The task is to convert them, and to figure out how to do the tests in storybook 7.
Currently this project is using react-action-state-path a custom build state and history management system for this project.
This task is about investigating using an existing state management system, or creating a new one.
Components, like the item component or the point component in the new ui, will get used in many places and often as children of other point components. Their 'state' will need to be preserved and restored if the user goes backward and forward.
Some components need to learn about actions in their children. For example, the RankPoints component shows a list of Points, and users are asked to decide which components are most, neutral, and least important. The parent component needs to get the information from the child of the point component that is selecting most/neurtal/least so it can count them, and limit the number of most/least, and also send the rankings to the database/api. These types of actions were part of RASP and could be part of the new system, or could be done separately.
This code runs on the server side, and then rehydrates and runs on the browser side.
One of the challenges of RASP is that we have to pass a unique key to each child, it would be nice if we didn't have to. And the the challenge is that the unique key needs to by unique even though the component is nested somewhere within other instances of the same component, and other components using the state management system. Generally, the key incorporates a path where each child's key is the parent key with something appended to it. And then that key is passed down to children.
Related code should be in the same place, ideally the same file. For example we use react-jss so our react components have their code and css in the same file. The state/action code for components that have state and actions should also be in that file.
See https://www.npmjs.com/package/@codastic/react-positioning-portal for a package to use to position the title text. I'm not saying this is the only option, but it looks good enough.
<StepFooter className="" style={}
active=false // true if the nextButton is active
onDone=()=>{} // the onDone function to be called by the Next Button
onBack=()=>{} // the function to call if the user hits the back button
/>
- [x] create stories
- [ ] the horizontal bar at the top should be part of the component.
- [ ] Use a media query of width less than theme.condensedWidthBreakPoint to determine this mode.
- [ ] if onDone or onBack is undefined, do not render that button - this could be the case for the first and last step
We need a page that shows the status of a discussion, in realtime.
Things to show:
create an API to call from the browser to get and subscribe to the data.
On the server side, when a subscription is active, the server monitors the active users though app/server/api.js this.users keeps track of the active users. We will need to create a way for that API to subscribe to it.
We can divide this into frontend and backend issues if desired.
mungo: git+https://github.com/Synaccord/mungo.git#mongo3_6 is a fork of a package that was created by past developer, long ago. It's benefit is that it allows the developer to create models (see app/models), where each model corresponds to a collection on the database, and a schema.
It also allows the database to be accesses through a single connection, that is shared by all the models.
In other projects (like github.com/EnCiv/undebates) mungo has been factored out in favor of mongo-models, but even that is loosing users and no longer being supported.
The goal of this issues is replace mungo, without using mongo-models, and without using mongoose (because it adds a whole additional layer of computation and complexity).
mungo has a few features that are not required, and probably more trouble than they are worth:
It's not just renaming the file ๐ it's convertings the stories to Storybook 7 format. See item.stories.js for a start.
There are some tests in stories/item.stories.jsx that have been commented out - these stories have additional interactions that just UI interactions and may need some more hooks or something in Storybook 7.
The original can be accessed by cloning the civil-pursuit repo into a new directory - civil-pursuit-temp
and then checking out the awesome-submit branch, and configuring node v10.16.2 - I recommend node version switcher and then running storybook
It's not just renaming the file ๐ it's convertings the stories to Storybook 7 format. See item.stories.js for a start.
create a story for app/components/type-components/qsort-why.jsx
The story should be in Storybook 7 Component Story Format, as we are working on moving the repo to that version.
these props were extracted out of the working prototype. Not all may be needed, or appropriate and should be pruned out:
{
"min": true,
"headlineAfter": true,
"className": "whole-border",
"visualMethod": "edit",
"buttons": [],
"item": {
"parent": {
"type": {
"_id": "5c5b5f1c3f2b9bcfdeac772c",
"name": "Answer",
"__v": 1,
"__V": 7,
"harmony": ["5c5b5f1c3f2b9bcfdeac7738", "5c5b5f1c3f2b9bcfdeac773b"],
"id": "PVOT4",
"component": { "component": "AskItemWhy", "className": "whole-border" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"visualMethod": "default",
"feedbackMethod": "hidden",
"mediaMethod": "disabled",
"referenceMethod": "disabled",
"subjectPlaceholder": "3 word title or key words",
"evaluateQuestion": "",
"parent": "5c5b5f1b3f2b9bcfdeac7724",
"instruction": "You probably want to see what other people are saying first. But, \"Wisdom of the Crowd\" theory says that independent answers yield the best results in the end. And, don't worry - everyone starts by first contributing their own, unbiased, independent answer."
},
"parent": {
"_id": "5d0137260dacd06732a1d814",
"id": "pvote",
"subject": "What one issue should โWe the Peopleโ unite and solve first to make our country even better?",
"description": "This task is testing an application for large scale online discussion that is unbiased, thoughtful, doesnโt require reading millions of answers, and leads to awesome results.\\We are only asking about a concern - an issue or problem, not about any possible solutions.\\Think about it before answering, think outside the box, think big and think about everyone in the country uniting on this.\\At the end, your feedback will be welcomed.",
"image": "https://res.cloudinary.com/hscbexf6a/image/upload/v1525373119/yabaz64oq89azgz05xqj.jpg",
"views": 3,
"promotions": 3,
"profiles": [
"DynamicSelector.Political Party.party",
"Gender",
"YearOfBirth",
"Race"
],
"popularity": {
"views": 3,
"promotions": 3,
"number": 100,
"ok": true
},
"subtype": {
"_id": "5cc0f5983f2b9bcfde6d64df",
"name": "Profile",
"__v": 1,
"__V": 7,
"harmony": ["5c5b5f1b3f2b9bcfdeac7721", "5c5b5f1b3f2b9bcfdeac7724"],
"id": "PVOTP",
"component": "ProfilePanel",
"instruction": "For this discussion we ask participants for demographic information to help us determine the diversity of the discussion.",
"buttonName": "Start Here",
"buttonTitle": {
"active": "Engage with your community on this",
"inactive": "Promote this discussion within your community to get enough people to engaged in this discussion"
}
},
"votes": 0,
"children": 0,
"harmony": { "harmony": 0, "types": [] },
"upvote": {
"total": 0,
"userDidUpvote": null,
"values": { "-1": 0, "+0": 0, "+1": 0 }
},
"type": {
"_id": "5c5b5f1b3f2b9bcfdeac771b",
"name": "Online Deliberation",
"__v": 1,
"__V": 7,
"harmony": [],
"id": "PVOT1",
"component": { "component": "Subtype", "className": "whole-border" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"visualMethod": "ooview"
},
"user": {
"tendency": "57412ecc5e6a2fdf017e397c",
"gender": "M",
"neighborhood": "Arrowhead",
"member_type": "Club",
"year_of_birth": 1962,
"party": "574f13c2c165f1790286ce01",
"race": ["574f13c2c165f1790286ce17"],
"starting_bloc_type": "LA'15",
"gender_identity": { "specify": "Male" },
"starting_bloc_race": ["White/Caucasian"]
}
},
"_id": "64437642c0e33001d4ccff23"
},
"type": {
"_id": "5c5b5f1c3f2b9bcfdeac7738",
"name": "Why it's Important",
"__v": 1,
"__V": 7,
"harmony": [],
"id": "PVOTM",
"component": { "component": "QSortWhy", "whyName": "most" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"feedbackMethod": "hidden",
"mediaMethod": "disabled",
"referenceMethod": "disabled",
"subjectPlaceholder": "title / key words",
"evaluateQuestion": "Why should everyone consider solving this issue?",
"instruction": "Of the issues you thought were most important, please give a brief explanation of why it's important for everyone to consider it"
},
"_id": "64437642c0e33001d4ccff24"
},
"rasp": { "shape": "edit", "depth": 6, "raspId": 8 },
"user": { "email": "[email protected]", "id": "000000000000000000000000" },
"classes": {
"item": "c018",
"item-buttons": "c019",
"item-text": "c0110",
"item-truncatable": "c0111",
"item-trunc-hint": "c0112",
"item-footer": "c0113",
"edit": "c0114",
"open": "c0115",
"peek": "c0116",
"truncated": "c0117",
"ooview": "c0118",
"title": "c0119",
"collapsed": "c0120",
"minified": "c0121",
"untruncate": "c0122",
"whole-border": "c0123",
"no-border": "c0124",
"error-message": "c0125",
"saving": "c0126",
"inputBorder": "c0127"
}
}
Add accessibility testing to our Storybook 7 configuration, and modify the kitchen-sink story to include the accessibility test.
Any accessibility issues don't have to be fixed, we just want to get to the point where we can run the tests and see what it shows.
https://storybook.js.org/docs/react/writing-tests/accessibility-testing
When I was doing "Compare Reasons Why it's Least Important" it was showing me reasons why it's important, but then my reason why it's less important at the end.
Here's the data from ReactActionStatePath.thiss for node 57. Sorry about the formatting
props
:
children
:
undefined
criterias
:
(2) [{โฆ}, {โฆ}]
evaluation
:
null
hideFeedback
:
true
hideFinish
:
true
itemId
:
"6439914d3819a7e68c25909c"
items
:
Array(4)
0
:
{_id: '5d0c086fe0991f1878908d49', id: 'yvG6e', subject: 'Homelessness', description: 'Homeless people need a stronger support network.', image: 'https://res.cloudinary.com/hscbexf6a/image/upload/โฆcale,r_8/a_0/v1415921565/xommyldfefjjvetenviv.jpg', โฆ}
1
:
{_id: '5d0c06b21a926990e9268db0', id: 'zKKWL', subject: 'Low impact', description: "There aren't nearly enough homeless for this to be important", image: 'https://res.cloudinary.com/hscbexf6a/image/upload/โฆcale,r_8/a_0/v1415921565/xommyldfefjjvetenviv.jpg', โฆ}
2
:
{_id: '5d0c02d35faf1ddafa7e9418', id: 'JARzx', subject: 'Homelessness', description: 'The issue of homelessness is not paramount', image: 'https://res.cloudinary.com/hscbexf6a/image/upload/โฆcale,r_8/a_0/v1415921565/xommyldfefjjvetenviv.jpg', โฆ}
3
:
{_id: '6439914d3819a7e68c25909c', id: 'THApq', subject: 'A local problem', description: "This is a local problem and is better addressed loโฆesn't seem like it will work the same everywhere.", image: 'https://res.cloudinary.com/hscbexf6a/image/upload/โฆcale,r_8/a_0/v1415921565/xommyldfefjjvetenviv.jpg', โฆ}
length
:
4
[[Prototype]]
:
Array(0)
limit
:
3
panel
:
type
:
component
:
{component: 'QSortRefine', whyName: 'least'}
createMethod
:
"hidden"
evaluateQuestion
:
"Which explanation is most convincing?"
feedbackMethod
:
"hidden"
harmony
:
[]
id
:
"PVOTl"
instruction
:
"Of these reasons others have given for why this issue is least important, please choose the most convincing explanation"
mediaMethod
:
"disabled"
name
:
"Compare Reasons Why it's Least Important"
promoteMethod
:
"hidden"
referenceMethod
:
"disabled"
subjectPlaceholder
:
""
__V
:
7
__v
:
1
_id
:
"5c5e07843f2b9bcfdeb17652"
[[Prototype]]
:
Object
[[Prototype]]
:
Object
This Button component will be the base of all of our buttons.
<Button >
<Button
className="" // may or may not be passed. Should be applied to the outer most tag, after local classNames
style={} // may or may not be passed, Should be applied to the outer most tag
onDone=()=>{} // a function that is called when the button is clicked. - if it exists
title="" // text to display on hover
disabled=false
disableOnClick=false // if true, the button gets disabled after click and stays disabled - prevents resubmission
>
text or <span></span>
</Button>
The width of the button shall be determined by the name passed, but can be over ridden by the style or class.
The base shall have the shape and border as shown in figma - based on the Secondary button.
Then create additional components using <Button>
, but passing classNames with styles to match the figma
<ModifierButton />
<SecondaryButtom />
<PrimaryButton />
<TextButton />
see figmaStretch goal:
It's not just renaming the file ๐ it's convertings the stories to Storybook 7 format. See item.stories.js for a start.
Currently using storybook 4.
The stories will have to change. storyOf is not supported anymore.
If it's not easy to do in bulk, do the upgrade and get one story working and create issues for other stories - with tips on what it took to convert.
If you go to https://civilpursuit.herokuapp.com/item/d,pvsum/S,d and the click on dissect of one of the items showing 5 of more than 5 - like "The income inequality problem" shows 5/9 and 5/8 - it will auto load the rest of the issues.
What's suppose to happen is the load more button shows up at the bottom, and the user clicks on it to load more.
I think an browser event is triggering the loadmore again.
look for loadmore in the code - need to figure out which component it is specifically.
Then after clicking on Dissect
Probably the problem is in app\components\rasp-panel-items.jsx in the loadmore function
Update to the LTS version of Node - 18.16.0
Update to Storybook 7.0
Update webpack and babel and other packages as necessary to get this to work.
Create a story for app/components/type-components/ask-item-why.jsx
The story should be in Storybook 7 Component Story Format, as we are working on moving the repo to that version.
These are the props extracted from the prototype that can be passed into the component, but the irrelevant props should be pruned out.
{
"min": true,
"headlineAfter": true,
"className": "whole-border",
"visualMethod": "edit",
"buttons": [],
"item": {
"parent": {
"type": {
"_id": "5c5b5f1c3f2b9bcfdeac772c",
"name": "Answer",
"__v": 1,
"__V": 7,
"harmony": ["5c5b5f1c3f2b9bcfdeac7738", "5c5b5f1c3f2b9bcfdeac773b"],
"id": "PVOT4",
"component": { "component": "AskItemWhy", "className": "whole-border" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"visualMethod": "default",
"feedbackMethod": "hidden",
"mediaMethod": "disabled",
"referenceMethod": "disabled",
"subjectPlaceholder": "3 word title or key words",
"evaluateQuestion": "",
"parent": "5c5b5f1b3f2b9bcfdeac7724",
"instruction": "You probably want to see what other people are saying first. But, \"Wisdom of the Crowd\" theory says that independent answers yield the best results in the end. And, don't worry - everyone starts by first contributing their own, unbiased, independent answer."
},
"parent": {
"_id": "5d0137260dacd06732a1d814",
"id": "pvote",
"subject": "What one issue should โWe the Peopleโ unite and solve first to make our country even better?",
"description": "This task is testing an application for large scale online discussion that is unbiased, thoughtful, doesnโt require reading millions of answers, and leads to awesome results.\\We are only asking about a concern - an issue or problem, not about any possible solutions.\\Think about it before answering, think outside the box, think big and think about everyone in the country uniting on this.\\At the end, your feedback will be welcomed.",
"image": "https://res.cloudinary.com/hscbexf6a/image/upload/v1525373119/yabaz64oq89azgz05xqj.jpg",
"views": 3,
"promotions": 3,
"profiles": [
"DynamicSelector.Political Party.party",
"Gender",
"YearOfBirth",
"Race"
],
"popularity": {
"views": 3,
"promotions": 3,
"number": 100,
"ok": true
},
"subtype": {
"_id": "5cc0f5983f2b9bcfde6d64df",
"name": "Profile",
"__v": 1,
"__V": 7,
"harmony": ["5c5b5f1b3f2b9bcfdeac7721", "5c5b5f1b3f2b9bcfdeac7724"],
"id": "PVOTP",
"component": "ProfilePanel",
"instruction": "For this discussion we ask participants for demographic information to help us determine the diversity of the discussion.",
"buttonName": "Start Here",
"buttonTitle": {
"active": "Engage with your community on this",
"inactive": "Promote this discussion within your community to get enough people to engaged in this discussion"
}
},
"votes": 0,
"children": 0,
"harmony": { "harmony": 0, "types": [] },
"upvote": {
"total": 0,
"userDidUpvote": null,
"values": { "-1": 0, "+0": 0, "+1": 0 }
},
"type": {
"_id": "5c5b5f1b3f2b9bcfdeac771b",
"name": "Online Deliberation",
"__v": 1,
"__V": 7,
"harmony": [],
"id": "PVOT1",
"component": { "component": "Subtype", "className": "whole-border" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"visualMethod": "ooview"
},
"user": {
"tendency": "57412ecc5e6a2fdf017e397c",
"gender": "M",
"neighborhood": "Arrowhead",
"member_type": "Club",
"year_of_birth": 1962,
"party": "574f13c2c165f1790286ce01",
"race": ["574f13c2c165f1790286ce17"],
"starting_bloc_type": "LA'15",
"gender_identity": { "specify": "Male" },
"starting_bloc_race": ["White/Caucasian"]
}
},
"_id": "64437642c0e33001d4ccff23"
},
"type": {
"_id": "5c5b5f1c3f2b9bcfdeac7738",
"name": "Why it's Important",
"__v": 1,
"__V": 7,
"harmony": [],
"id": "PVOTM",
"component": { "component": "QSortWhy", "whyName": "most" },
"createMethod": "hidden",
"promoteMethod": "hidden",
"feedbackMethod": "hidden",
"mediaMethod": "disabled",
"referenceMethod": "disabled",
"subjectPlaceholder": "title / key words",
"evaluateQuestion": "Why should everyone consider solving this issue?",
"instruction": "Of the issues you thought were most important, please give a brief explanation of why it's important for everyone to consider it"
},
"_id": "64437642c0e33001d4ccff24"
},
"rasp": { "shape": "edit", "depth": 6, "raspId": 8 },
"user": { "email": "[email protected]", "id": "000000000000000000000000" },
"classes": {
"item": "c018",
"item-buttons": "c019",
"item-text": "c0110",
"item-truncatable": "c0111",
"item-trunc-hint": "c0112",
"item-footer": "c0113",
"edit": "c0114",
"open": "c0115",
"peek": "c0116",
"truncated": "c0117",
"ooview": "c0118",
"title": "c0119",
"collapsed": "c0120",
"minified": "c0121",
"untruncate": "c0122",
"whole-border": "c0123",
"no-border": "c0124",
"error-message": "c0125",
"saving": "c0126",
"inputBorder": "c0127"
}
}
<Opener className="" style={}
defaultValue="open" || "closed"
onDone=()=>"open"||"closed" // a function to call with the new state
/>
This is used in components like the #35 the Point Group component for opening and closing
This component will render the demographic info that is shown within a <Point />
. It's in a separate component because we are likely to go through lots of iterations of what demographic info we show and how.
<DemInfo demInfo={} classname={} style={} />
see React component guidelines and notes
the demInfo property will contain some demographic info about the user who created the point. It will not contain identifying information.
The user schema is here:
user schema
For starters, we should just show the state, age, and political party.
We should not show the first name as depicted in the design - and it won't be there.
In the latest figma we are showing the user's political party rather than their first name. We want people to feel comfortable that they aren't being identified.
by default this component should return a span, but classname and style should override that.
Figma for desktop
Figma for smartphone version
<TopNavBar style={} className=""
menu=[{name: "", func: ()=>{}},[]] // an element of this array is either a menuItem, or and array of menuItems
mode?='light'|'dark'
defaultValue=string // the initial name of the menu item to underline
>
The Point Group component accepts pointObj and vState as props
export type pointObj = {
_id: MongoId,
subject: string,
description: string,
groupedPoints?: [pointObj]
}
<PointGroup
pointObj: {}
vState: '' // same as Point component
>
To each Point Component #23 it will pass a pointObj, it will add a Select as Lead component as an additional child - if necessary.
See the figma design for the various states. This component covers the "Edit Lead" and "Select Lead" cases shown in figma.
The Point Components will render in a flex box that could be one or two columns wide - depending on the view port.
The Point Group component will render in it's various states bases on the value of state.
For example, collapsed and open.
<ShowDualPointList className={} style={}
leftPoints= [] // can be a point, or a pointGroup
leftHeader= ""
rightList=[] // can be a point, or a pointGroup
rightHeader=""
vState="collapsed"||"expanded"
/>
Note we are going to add a collapsed state to the Point component, so this component can render PointComponents and pass in a collapsed vState to show the data.
There are many common properties for the webpack config in
.storybook/main.js - in webpackFinal
webpack-dev.config.js
webpack-prod.confi.js
create a new file
webpack-common.config.js
with what's common, and then import it into each of those places and use "weback-merge" as in main.js to create the final version.
test with npm run storybook
npm run dev
and npm start
you will need to have MONGODB_URI setup to do this.
<PointInput>
<PointInput
style={}
className=""
onDone=()=>(valid, {subject: "", description: "", ...})
defaultValue={subject: "", description: "", ...}
/>
See undebate-ssp/app/components/script-text-input.js for a head start on this.
Storybook
Figma
see also
Figma ui/radial
see also disabled
<PairCompare
mainPoint={} the point object that the point list is about.
pointList=[] // an array of pointObj
onDone=()=>{valid: false, value={}} // function to call with the winning object, or false, null if now winner.
onDone is called with value set to the winning object, or null if no object won (like the user clicked neither every time)
onDone valid is true if the pointList, and false if its not though it's not clear when onDone would be called other than on completion.
When you get to step 7 - Review, it keeps calling loadMore in app/components/store/items.jsx
Create the StepBar component
<StepBar className="" style={},
steps=[{name: "", title: "", complete: false}],
current=0, // integer referring to the current step the user is on
onDone=()=>nextStep // a function to call with the index of the step that the user clicks on
>
see unpoll/app/components/nav-bar.js for a start - but there are differences.
On Desktop
On Smartphone
When the user comes back to answer a deliberation, they have to answer the question again, but then they see all the items they previously sorted, plus 9 new items. And if they keep coming back, the list keeps growing.
What we need:
If the user hasn't completed the deliberation, then the user should not have to enter a new answer, and should be taken to the next step that has to be completed.
If the user has completed the deliberation, (or has no uncompleted deliberation), then the user should start a new one, from the beginning, without all the previous items.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.