Git Product home page Git Product logo

civil-pursuit's People

Contributors

boyuan-yu avatar co2-git avatar ddfridley avatar edmundj0 avatar hansgit9033 avatar jojoliu66 avatar julian-cardone avatar justestif avatar kyleslugg avatar synaccord avatar taylorcornwall766 avatar zilinfg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

civil-pursuit's Issues

ReviewPoint component

Render one point for review in the review step.

image

Figma

<ReviewPoint className={}
    read=false
    rank=""
    subject=""
    description=""
    leftPointList=[]
    rightPointList=[]
    onDone=()=>{}
/>
  • if not read, and not opened, the Rank Component #36 is rendered inactive
  • if the chevron or Opener component #48 is clicked on, then the component opens and renders the ShowDualPointList #57 component.
  • Implement the Expand Chart button, keeping the state locally, and using with the ShowDualPointList
  • the Rank component can then be used
  • onDone to this component is passed to the Rank component
  • when onDone is called, this component should go back into the closed state
  • Create stories that exercise the different states and actions

StepIntro component

image

Figma

<StepIntro className="" style={}
    subject=""
    description=""
/>
  • description may be multiple paragraphs separated by \n.
  • create story with a 1 paragraph and 2 paragraph case
  • note the horizontal line at the bottom should be part of this component

GroupingStep

image

Figma

<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 
/>
  • Use a media query of width less than theme.condensedWidthBreakPoint to determine when to switch to 1 column mode (for smartphones).

Storybook

  • User 10 points for the test case
  • Create a story case for each state, progressively use play() to simulate the user interactions to get to each state.
  • Test the case when groupedPointList is already populated
  • Test the case when shared={}, and shared={startingPointList: undefined} and shared={startingPointList: []}

Stretch Goal

  • When point grouping is complete, use animation to show the points combining at the bottom, and the rest of the points moving into their new positions.

HowDoYouFeel component

image

Figma

<HowDoYouFeel onDone=()=>{}/>
  • This component renders the question, and the three buttons.
  • When the user press one of the button, it's onDone will be called, and an API call will be made.
  • After the onDone is called, this componet will call it's onDone with {valid: true, value: answer}
  • Uses #43 Text Button component

The API call information will be provided later, for now just render the component.

  • Create a Story to exercise the component.

RankStep component

image

Figma

<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=()=>({})
/>
  • The user must rank 2 as most important, and 1 as least important, and the rest neutral. - the instructions in the UI are currently incorrect. For now, until we update the UI, build this component without checking for most and least - so you don't have to deal with the 'Oops' state in the UI. If there are less than 5 points, then the Most/Least are not enforced.
  • Render the list in 2 columns. Use a media query of width less than theme.condensedWidthBreakPoint to determine when to switch to 1 column mode (for smartphones).
  • When the user ranks a point, add or update it in the rankList
  • after initial render, if there's a change in props, and after the user ranks an item, call onDone({valid: doneCount===totalCount, value: doneCount / totalCount})
  • uses the #23
  • uses the #36 as a child passed to the point component
  • uses the #35
  • Create a story for this
  • Create a story case where there are 10 points, and the rank list is empty
  • Create a story case where there are 10 points, and simulate the user ranking them so you get 2 most, 1 least, and 7 neutral. Validate the rankList
  • Create a story cases where there are 7 points.
  • Create more story cases to test it out.

PointInput component

image

figma

<PointInput style={} className=""
     question="" 
     why=""
     shared={
          startingPointList=[]
          whyMostList=[]
     }
/>

TBD
This issue still needs some definition.

  • api call to write write the answers to the 2 questions
  • if the user is returning to this discussion, and the answers have already been given how is that passed.

Node 18

Get this working on node version 18

Grouping Similar Items

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.

Point Component

  • Create a new react component called Point
  • Create a story for it

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:

  • subject: short string
  • description: long string with multiple lines and paragraphs
  • vState: a string representing the visual state - the way the information will be rendered
  • children: react children - if there are children, they will be rendered within the component
  • styles: object merge these styles into the outer div of the component.
  • classname: merge these classnames into the outer div of the component
  • as you decode figma, other parameter's may be needed besides vState. If so, lets discuss.

image
Figma

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).

image
  • the width of the component is determined by the parent, and the component should not have an outer margin
  • the line that says First Name | 45, UT should be the <DemInfo {...otherProps} /> component.
    otherProps is a common patter here:
const {subject, description, vState, children, styles, classname, ...otherProps} = props
  • The point component needs to render a "collapsed" vState that just renders the subject. See figma

image

User didn't notice input for title/summary

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.

  • How do we update the UI to make it more apparent to the user they need to fill out that second part?

We the People-2

To duplicate this, start here: https://civilpursuit.herokuapp.com/item/pvote

  1. Click Start Here
  2. Enter Demographic info
  3. Click accpet the terms and Skip

Then you will be at the input page

finish converting stories/item-stories.js

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.

RASP State Management Replacement Investigation

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.

Here are the user level requirements:

  1. User's need to be able to use the browser's backward and forward buttons to move through the discussion process.
  2. Users need to be able to hit refresh and get back to where they are in the discussion process
  3. Some state changes are due to user interaction, like clicking on the next button. Some state changes are due to non-user events, like data becoming available from api calls. The back/forward browser actions are for back/forward of user interactions, not api stuff.
  4. If the user changes something through the UI that is pushed to the server in realtime, if the users goes back in the browser, the current - not the past - content of the database needs to be shown.

Internal requirements:

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.

Design/coding philosophy requirements

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.

ReviewPointList component

image

Figma

<ReviewPointList
    ReviewPoints=[{point, leftPoints, RightPoints, rank}]
    onDone=()=>{valid,value} // valid when all the points have been read and ranked value is %done
/>

This component builds on (requires) the following

  • #58

  • #57

  • this component keeps track of the rank and read value for each point and updates the database with changes to rank

  • Create story for this component, rending a number for #58 components

StepFooter component

image

Figma

<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

Live Discussion Status Page

We need a page that shows the status of a discussion, in realtime.

Things to show:

  • The number of participants
  • Something showing what states have participants - perhaps a US Map and the states change color based on number of participants.
  • political party
  • gender
  • race

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.

factor out mungo

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:

  1. migrating the data in a collection from an old version to a new version. This is the migrations subdirectory
  2. handling initialization data - this is the /fixtures directory. This idea is straightforward - but it's pretty easy to just use a json file and a command line to initialize the data.

StatusBadge component

image

Figma

<StatusBadge style={} className=""
   name=""
   status="inactive", "complete", "progress" // only one
   number=undefined  // if undefined don't show the number, else show number
>
  • renders as a span
  • Create story

additional tests for item.stories.jsx

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

Story for QSortWhy

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"
  }
}

Compare Reasons Why it's Least Important - reasons seemed to be why it's important #1

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

Button components

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>
  • className may have 'hover' in it. This will occur when the user is hovering over the parent component, and the parent component wants the button to go into the hover state as well. In the styles definition, .hover (the class name) should do the same thing as :hover (the pseudo class).

The width of the button shall be determined by the name passed, but can be over ridden by the style or class.
image

figma

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 figma
  • colors and padding and such for styles should be in theme.js - think of reusable names
  • Create Storybook cases for each of the buttons and exercise their props

Stretch goal:

Upgrade to Storybook 7

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.

prematurely loading more

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.

image

Then after clicking on Dissect
image

Probably the problem is in app\components\rasp-panel-items.jsx in the loadmore function

Story for AskItemWhy

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 component

image

Figma

<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

  • if user clicks on it, change state and call onDone, change the direction of the chevron
  • returns a span (not a div)
  • Create a story

DemInfo

  • create a new component DemInfo (stands for demographic info)
  • create a story for it

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.

image

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.

Figma is here

by default this component should return a span, but classname and style should override that.

User feedback

Scrolling was jumpy.
When selecting issues (most/lease/neutral) - the warning message was not clear.
image

TopNavBar component

image

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
>

Figma for Dark Mode

  • Use a media query of width less than theme.condensedWidthBreakPoint to determine this mode.
  • In smartphone mode, when the hamburger is expanded, show the menu options full width, centered.
  • render the full width of the parent
  • create stories
  • For the user/login info we have a component we want to use user-or-signup but we are still figuring out how to style it, and how to import it from there. For now, create a placeholder component.

Point Group Component

  • Create a PointGroup react component.

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.

figma
image

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.

  • create a story that renders this component in each of its various states.
  • default state
  • edit state
  • view state
  • select lead state
  • collapsed - The point component needs to render a "collapsed" vState that just renders the subject. See figma

image

  • same vStates as pointComponent
  • the component needs to implement the actions to move from state to state - for example - but in development this will need to be expanded:
  • From the default state (showing only the lead item) if the user clicks on the chevron - change to the view state
  • If the user clicks the edit button, move to the edit state

ShowDualPointList

image
Figma

<ShowDualPointList className={} style={}
    leftPoints= []  // can be a point, or a pointGroup
    leftHeader= ""
    rightList=[] // can be a point, or a pointGroup
    rightHeader=""
    vState="collapsed"||"expanded"
/>
  • should render as 2 columns within width of the parent
  • each point should be rendered using the #35 and applying the appropriate vState, plus a className to apply the backgroundColor
  • Create stories
  • story for case where props are undefined
  • story for case where lists are empty
  • story data should include some pointGroups
  • stories for the 2 different vState's
  • story with a mobile width parent

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.

Factor out webpack-common.config.js

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 component

  • <PointInput>
<PointInput
    style={}
    className=""
    onDone=()=>(valid, {subject: "", description: "", ...})
    defaultValue={subject: "", description: "", ...} 
/>
  • valid is true when there is both a subject and description of at least one word, and not more than the maximum number of words.
  • shows and updates the word count as the user types
  • calls onDone when the users leaves the input field, meaning onBlur
  • height of the description field will grow as the user types more
  • note this component should have no gap between the input fields and the left/right/top/bottom. That should be padding set by the parent component.
image

See undebate-ssp/app/components/script-text-input.js for a head start on this.

Storybook

  • case for defaultValue undefined
  • case for defaultValue is empty meaning {}
  • case for text input causing description field to grow
  • case for user enters too much text and the field turns red and onDone is called with invalid

Rank Component

  • Create the Rank component
  • Create a story that renders the component and exercises all it's states
    <Rank
    disabled=false
    defaultValue: undefined or '', or a choice
    onSelected=()=>return choice
    />
    choices are Most, Neutral, or Least

image

Figma
see also
Figma ui/radial
see also disabled

Item or [ListofItems]

We need to update the codebase to support grouping, meaning that an Item displayed, could really be a list of items.
In the unpoll project this is CardStack

It's unclear if CardStack can be turned into a component that can be used in both places, with different styling, but that's an ideal.

PairCompare component

image

Figma

<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.

  • Style Guide applies
  • Show the first two points from the list
  • If only one point, show it and let the user click it, or neither (and neither should be none in this case)
  • After the user clicks one, the other one slides away (animated) and a new one slides into place. In desktop they slide in from the top. on mobile the slide in from the right.
  • the count at the top updates as the user proceeds
  • if the user clicks neither, both points change
  • create a story
  • use play() steps in the story to go through the steps of comparing 5 points.
  • If the user clicks start over, call onDone with {valid: false, value: null}

WhyInput component

image
Figma

<WhyInput
    point=pointObj
    defaultValue?=pointObj
    onDone?=()=>{valid: true if the obj is valid, valid: pointObj}
/>
  • Uses the #44 to gather input
  • Users #23 to render the Why Point
  • On initial render, and whenever the user leaves the input area, onDone is called.
  • Create a Story

StepBar Component

image

Figma

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.

  • Create stories
  • User storybook play to exercise the features

On Desktop

  • user can scroll left and right through the steps
  • user can hover over a step and read more details (the title)
  • user can click on an complete step, and that will cause onDone to be called with the index of that step
  • user can not click on an incomplete step
  • whether the current step is complete or not, clicking on it does not call onDone
  • the component is as wide as it's parent

On Smartphone

  • User a media query of width less than theme.condensedWidthBreakPoint to determine this mode. And not the width will be something like 50rem. (please add it to the theme file if it is not there).
  • the current step is shown
  • if the user opens the selector, show all the items that will fit down to the bottom of the viewport, then allow scrolling.
  • user can select items that are complete, but not items that are incomplete
  • the component is as wide as it's parent

  • stretch goal - show the title text if the user long presses on a step

When user returns, the list grows too large

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.