Skip to content

Commit

Permalink
feat(storybook,Stat): initial string Stat component with story
Browse files Browse the repository at this point in the history
Given that @ramfox is working on the sliding-panel stuff, and I want to work on starts charts, this is a good chance to bring storybook into the mix.

I've also started building out a basic Stat component that displays frequencies if they exist. There's a *lot* of variability to stats frequency counts, so it's worth trying out different stats output for visual edge cases.

I ended up roughing-in https://nivo.rocks as a charting library. It's configuration-as-docs is an incredible concept.
  • Loading branch information
b5 committed Nov 14, 2019
1 parent f1abc5e commit 2f9443d
Show file tree
Hide file tree
Showing 10 changed files with 4,602 additions and 189 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"presets": ["env"],
"presets": ["@babel/preset-env"],
"plugins": ["react-hot-loader/babel"]
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ main.js
main.js.map

.idea
storybook-static
3 changes: 3 additions & 0 deletions .storybook/addons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-notes/register-panel';
4 changes: 4 additions & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { configure } from '@storybook/react';

// automatically import all files ending in *.stories.tsx
configure(require.context('../stories', true, /\.stories\.tsx$/), module);
29 changes: 29 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module.exports = ({ config }) => {
config.module.rules.push({
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
babelrc: false,
presets: [
[
'@babel/preset-env',
{ targets: { browsers: 'last 2 versions' } } // or whatever your project requires
],
'@babel/preset-typescript',
'@babel/preset-react'
],
plugins: [
// plugin-proposal-decorators is only needed if you're using experimental decorators in TypeScript
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
'react-hot-loader/babel'
]
}
}
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
85 changes: 85 additions & 0 deletions app/components/stats/Stat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ResponsiveBar } from '@nivo/bar'
import * as React from 'react'

interface StatProps {
height: number
data: Record<string, any>
}

const Stat: React.FunctionComponent<StatProps> = (props: StatProps) => {
const { data, height = 250 } = props
switch (data.type) {
case 'string':
return <StringStat data={data} height={height} />
default:
return (
<span>
{data.count && <p>Count: {data.count}</p>}
</span>
)
}
}

export default Stat

const StringStat: React.FunctionComponent<StatProps> = (props: StatProps) => {
const { data, height } = props
let frequencies

if (data.frequencies) {
frequencies = Object.keys(data.frequencies).reduce((acc, key) => {
let label = key
if (label.length > 20) {
label = label.slice(0, 18) + '...'
} else if (label === '') {
label = '""'
}
acc.push({
id: key,
label,
value: data.frequencies[key]
})
return acc
}, [])
}

return (
<div style={{ height: height }}>
<p>Count: {data.count}<br/>Min Chracter Length: {data.minLength}<br/>Max String Length: {data.maxLength}<br/></p>
{frequencies && <ResponsiveBar
data={frequencies}
margin={{ top: 50, right: 60, bottom: 50, left: 60 }}
padding={0.3}
colors={{ scheme: 'nivo' }}
tooltip={({ value, color, data }) => (
<strong style={{ color }}>
{data.label}: {value}
</strong>
)}
theme={{
tooltip: {
container: {
background: '#333'
}
}
}}
borderColor={{ from: 'color', modifiers: [ [ 'darker', 1.6 ] ] }}
axisLeft={{
tickSize: 5,
tickPadding: 5,
tickRotation: 0,
legend: 'count',
legendPosition: 'middle',
legendOffset: -40
}}
axisBottom={null}
labelSkipWidth={12}
labelSkipHeight={12}
labelTextColor={{ from: 'color', modifiers: [['darker', 1.6]] }}
animate={true}
motionStiffness={90}
motionDamping={15}
/>}
</div>
)
}
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
"build-renderer": "cross-env NODE_ENV=production node ./node_modules/webpack/bin/webpack --mode=production --config webpack.config.production.js --progress --profile --colors",
"build": "npm run build-main && npm run build-renderer",
"start": "cross-env NODE_ENV=production electron ./app/",
"storybook": "start-storybook -p 6006",
"start-hot": "cross-env HOT=1 NODE_ENV=development electron ./app/main.development",
"postinstall": "electron-builder install-app-deps",
"dev": "npm run hot-server -- --start-hot",
"pack": "npm run build && electron-builder --dir",
"dist": "npm run build && electron-builder",
"lint": "./node_modules/.bin/eslint --ext tsx --ext ts app/",
"cleanup": "mop -v"
"cleanup": "mop -v",
"build-storybook": "build-storybook"
},
"jest": {
"moduleNameMapper": {
Expand Down Expand Up @@ -125,6 +127,10 @@
],
"homepage": "https://qri.io",
"devDependencies": {
"@storybook/addon-actions": "^5.2.6",
"@storybook/addon-links": "^5.2.6",
"@storybook/addon-notes": "^5.2.6",
"@storybook/addons": "^5.2.6",
"@types/classnames": "2.2.9",
"@types/enzyme": "3.10.3",
"@types/history": "4.7.3",
Expand Down Expand Up @@ -211,6 +217,9 @@
"@fortawesome/free-regular-svg-icons": "5.11.2",
"@fortawesome/free-solid-svg-icons": "5.11.2",
"@fortawesome/react-fontawesome": "0.1.7",
"@nivo/bar": "^0.59.2",
"@storybook/cli": "^5.2.6",
"@storybook/react": "^5.2.6",
"@types/webpack-env": "1.14.1",
"babel-loader": "8.0.6",
"change-case": "3.1.0",
Expand Down
37 changes: 37 additions & 0 deletions stories/0-Stats.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react'
import Stat from '../app/components/stats/Stat.tsx'
import statsData from './data/nyc_report_family_justice_center_stats.json'

export default {
title: 'Stats',
parameters: {
notes: `feeding different data to the stats component.
stats data from the [nyc fjc report](https://data.cityofnewyork.us/Social-Services/Annual-Report-on-Family-Justice-Center-Client-Sati/g62n-cz6a)`
}
}

export const zero = () => <Stat data={statsData[0]} />

zero.story = {
name: 'Many Long String',
}

export const one = () => <Stat data={statsData[1]} />

one.story = {
name: 'Empty String'
}

export const two = () => <Stat data={statsData[2]} />

two.story = {
name: 'Yes/No/Blank String'
}


export const three = () => <Stat data={statsData[3]} />

three.story = {
name: 'Languages String'
}
157 changes: 157 additions & 0 deletions stories/data/nyc_report_family_justice_center_stats.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
[
{
"count": 400,
"frequencies": {
"Blank": 5,
"Child Services (children's counseling/playroom)": 6,
"Civil Legal Services": 39,
"Civil Legal Services|Child Services (children's counseling/playroom)": 2,
"Counseling Services": 37,
"Counseling Services|Child Services (children's counseling/playroom)": 4,
"Counseling Services|Other (please specify)": 2,
"Criminal Justice/NYPD Services": 3,
"Economic Empowerment Services": 6,
"Housing Information/Advocacy": 7,
"Housing Information/Advocacy|Safety Planning": 2,
"Met with Case Manager": 75,
"Met with Case Manager|Child Services (children's counseling/playroom)": 2,
"Met with Case Manager|Civil Legal Services": 20,
"Met with Case Manager|Civil Legal Services|Counseling Services": 4,
"Met with Case Manager|Civil Legal Services|Housing Information/Advocacy": 5,
"Met with Case Manager|Civil Legal Services|Housing Information/Advocacy|Counseling Services": 3,
"Met with Case Manager|Civil Legal Services|Housing Information/Advocacy|Shelter Information/Advocacy|Safety Planning|Counseling Services|Psychiatric Services (medication management/Health and Hospital)|Child Services (children's counseling/playroom)|Economic Empowerment Services|Public Benefits Information/Services|Criminal Justice/NYPD Services|Practical Support (ex: clothing or food donations)": 2,
"Met with Case Manager|Civil Legal Services|Housing Information/Advocacy|Shelter Information/Advocacy|Safety Planning|Counseling Services|Psychiatric Services (medication management/Health and Hospital)|Child Services (children's counseling/playroom)|Economic Empowerment Services|Public Benefits Information/Services|Criminal Justice/NYPD Services|Practical Support (ex: clothing or food donations)|Spiritual Support Services": 3,
"Met with Case Manager|Civil Legal Services|Safety Planning": 3,
"Met with Case Manager|Civil Legal Services|Safety Planning|Counseling Services": 2,
"Met with Case Manager|Civil Legal Services|Shelter Information/Advocacy|Safety Planning|Practical Support (ex: clothing or food donations)": 2,
"Met with Case Manager|Counseling Services": 7,
"Met with Case Manager|Economic Empowerment Services": 2,
"Met with Case Manager|Housing Information/Advocacy": 7,
"Met with Case Manager|Housing Information/Advocacy|Shelter Information/Advocacy": 3,
"Met with Case Manager|Housing Information/Advocacy|Shelter Information/Advocacy|Safety Planning|Counseling Services|Economic Empowerment Services|Public Benefits Information/Services|Practical Support (ex: clothing or food donations)": 2,
"Met with Case Manager|Other (please specify)": 5,
"Met with Case Manager|Practical Support (ex: clothing or food donations)": 3,
"Met with Case Manager|Public Benefits Information/Services": 3,
"Met with Case Manager|Safety Planning": 3,
"Met with Case Manager|Shelter Information/Advocacy": 6,
"Met with Case Manager|Shelter Information/Advocacy|Safety Planning|Counseling Services": 2,
"Other (please specify)": 12,
"Psychiatric Services (medication management/Health and Hospital)": 2,
"Safety Planning": 5,
"Spiritual Support Services": 2
},
"maxLength": 479,
"minLength": 5,
"type": "string",
"unique": 102
},
{
"count": 400,
"frequencies": {
"": 367,
"Computer usage.": 2
},
"maxLength": 154,
"minLength": 0,
"type": "string",
"unique": 31
},
{
"count": 400,
"frequencies": {
"Blank": 44,
"No": 251,
"Yes": 105
},
"maxLength": 5,
"minLength": 2,
"type": "string"
},
{
"count": 400,
"frequencies": {
"": 293,
"Arabic": 2,
"Bengali": 2,
"French": 2,
"Mandarin": 5,
"Other": 7,
"Russian": 5,
"Spanish": 65,
"Unknown": 18
},
"maxLength": 8,
"minLength": 0,
"type": "string",
"unique": 1
},
{
"count": 400,
"frequencies": {
"": 388,
"Chinese": 2,
"English": 5,
"Polish": 2
},
"maxLength": 14,
"minLength": 0,
"type": "string",
"unique": 3
},
{
"count": 400,
"frequencies": {
"": 62,
"All.": 2,
"Case worker": 2,
"Everything": 3,
"Everything.": 2,
"Legal help": 2,
"The information we are seeking": 2,
"Yes": 2
},
"maxLength": 446,
"minLength": 0,
"type": "string",
"unique": 323
},
{
"count": 400,
"frequencies": {
"Blank": 22,
"No": 4,
"Yes": 374
},
"maxLength": 5,
"minLength": 2,
"type": "string"
},
{
"count": 400,
"frequencies": {
"Bronx": 142,
"Brooklyn": 84,
"Manhattan": 58,
"Queens": 89,
"Staten Island": 27
},
"maxLength": 13,
"minLength": 5,
"type": "string"
},
{
"count": 400,
"frequencies": {
"Arabic": 2,
"English": 270,
"Polish": 4,
"Russian": 5,
"Simplified Chinese": 17,
"Spanish": 100
},
"maxLength": 18,
"minLength": 6,
"type": "string",
"unique": 2
}
]
Loading

0 comments on commit 2f9443d

Please sign in to comment.