Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Drop papaparse & create CSV rows w/ custom code
Browse files Browse the repository at this point in the history
- remove papaparse library
- create utility function for generating CSV row strings in order to
circumvent a bug whereby JSON.parse would occasionally cast OAR ID shas
into numbers
- add tests for CSV parsing function
- rename app from "redpanda" to "open apparel registry" in package.json
  • Loading branch information
Kelly Innes committed Mar 4, 2019
1 parent 5dbbf6a commit dae70dc
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 45 deletions.
7 changes: 2 additions & 5 deletions src/app/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "redpanda",
"name": "open-apparel-registry",
"version": "0.1.0",
"license": "MIT",
"private": true,
Expand All @@ -10,11 +10,9 @@
"axios": "0.18.0",
"core-js": "2.6.4",
"file-saver": "2.0.0",
"json2csv": "4.1.6",
"immutability-helper": "2.9.0",
"lodash": "4.17.11",
"mapbox-gl": "0.52.0",
"papaparse": "4.6.3",
"prop-types": "15.6.2",
"react": "16.7.0",
"react-copy-to-clipboard": "5.0.1",
Expand All @@ -40,8 +38,7 @@
"build": "react-scripts build",
"test": "CI=1 react-scripts test",
"lint": "eslint src/ --ext .js --ext .jsx",
"eject": "react-scripts eject",
"deploy": "npm run build && firebase deploy"
"eject": "react-scripts eject"
},
"devDependencies": {
"@babel/cli": "7.0.0-beta.49",
Expand Down
138 changes: 137 additions & 1 deletion src/app/src/__tests__/utils.tests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-env jest */
/* eslint-disable no-useless-escape */

const mapValues = require('lodash/mapValues');
const isEqual = require('lodash/isEqual');
Expand Down Expand Up @@ -44,6 +45,9 @@ const {
makeResetPasswordEmailURL,
getTokenFromQueryString,
makeResetPasswordConfirmURL,
joinDataIntoCSVString,
caseInsensitiveIncludes,
sortFacilitiesAlphabeticallyByName,
} = require('../util/util');

const {
Expand Down Expand Up @@ -305,7 +309,7 @@ it('gets the value from an event on a DOM input', () => {
expect(getValueFromEvent(mockEvent)).toEqual(value);
});

it('gets the checked state from an even on a DOM checkbox input', () => {
it('gets the checked state from an event on a DOM checkbox input', () => {
const checked = true;
const mockEvent = {
target: {
Expand Down Expand Up @@ -716,3 +720,135 @@ it('gets a `token` from a querystring', () => {

expect(getTokenFromQueryString(missingQueryString)).toBe(expectedMissingQueryStringMatch);
});

it('joins a 2-d array into a correctly escaped CSV string', () => {
const numericArray = [
[
1,
2,
],
[
3,
4,
],
];
const expectedNumericArrayMatch = '1,2\n3,4\n';
expect(joinDataIntoCSVString(numericArray)).toBe(expectedNumericArrayMatch);

const stringArray = [
[
'hello',
'world',
],
[
'foo',
'bar',
],
];
const expectedStringArrayMatch = '"hello","world"\n"foo","bar"\n';
expect(joinDataIntoCSVString(stringArray)).toBe(expectedStringArrayMatch);

const mixedArray = [
[
1,
'hello',
],
[
2,
'world',
],
];
const expectedMixedArrayMatch = '1,"hello"\n2,"world"\n';
expect(joinDataIntoCSVString(mixedArray)).toBe(expectedMixedArrayMatch);

const escapedArray = [
[
'foo, bar, baz',
'hello "world"',
],
[
'foo, "bar", baz',
'hello, world',
],
];
const expectedEscapedArrayMatch =
'"foo, bar, baz","hello \"world\""\n"foo, \"bar\", baz","hello, world"\n';
expect(joinDataIntoCSVString(escapedArray)).toBe(expectedEscapedArrayMatch);
});

it('checks whether one string includes another regardless of char case', () => {
const uppercaseTarget = 'HELLOWORLD';
const lowercaseTest = 'world';
const lowercaseTarget = 'helloworld';
const uppercaseTest = 'WORLD';
const uppercaseNonMatchTest = 'FOO';
const lowercaseNonMatchTest = 'foo';

expect(caseInsensitiveIncludes(uppercaseTarget, lowercaseTest)).toBe(true);
expect(caseInsensitiveIncludes(lowercaseTarget, uppercaseTest)).toBe(true);
expect(caseInsensitiveIncludes(lowercaseTarget, lowercaseTest)).toBe(true);
expect(caseInsensitiveIncludes(uppercaseTarget, uppercaseTest)).toBe(true);

expect(caseInsensitiveIncludes(uppercaseTarget, lowercaseNonMatchTest)).toBe(false);
expect(caseInsensitiveIncludes(lowercaseTarget, uppercaseNonMatchTest)).toBe(false);
expect(caseInsensitiveIncludes(lowercaseTarget, lowercaseNonMatchTest)).toBe(false);
expect(caseInsensitiveIncludes(uppercaseTarget, uppercaseNonMatchTest)).toBe(false);
});

it('sorts an array of facilities alphabetically by name without mutating the input', () => {
const inputData = [
{
properties: {
name: 'hello World',
},
},
{
properties: {
name: 'FOO',
},
},
{
properties: {
name: 'Bar',
},
},
{
properties: {
name: 'baz',
},
},
];

const expectedSortedData = [
{
properties: {
name: 'Bar',
},
},
{
properties: {
name: 'baz',
},
},
{
properties: {
name: 'FOO',
},
},
{
properties: {
name: 'hello World',
},
},
];

expect(isEqual(
sortFacilitiesAlphabeticallyByName(inputData),
expectedSortedData,
)).toBe(true);

expect(isEqual(
inputData,
expectedSortedData,
)).toBe(false);
});
57 changes: 57 additions & 0 deletions src/app/src/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@ import size from 'lodash/size';
import negate from 'lodash/negate';
import omitBy from 'lodash/omitBy';
import isEmpty from 'lodash/isEmpty';
import isNumber from 'lodash/isNumber';
import values from 'lodash/values';
import flow from 'lodash/flow';
import noop from 'lodash/noop';
import compact from 'lodash/compact';
import startsWith from 'lodash/startsWith';
import head from 'lodash/head';
import replace from 'lodash/replace';
import trimEnd from 'lodash/trimEnd';
import includes from 'lodash/includes';
import lowerCase from 'lodash/lowerCase';
import { featureCollection, bbox } from '@turf/turf';
import { saveAs } from 'file-saver';

Expand All @@ -32,6 +37,8 @@ import {

import { createListItemCSV } from './util.listItemCSV';

import { createFacilitiesCSV } from './util.facilitiesCSV';

export function DownloadCSV(data, fileName) {
saveAs(
new Blob([data], { type: 'text/csv;charset=utf-8;' }),
Expand All @@ -50,6 +57,9 @@ export const downloadListItemCSV = list =>
`${list.id}_${list.name}_${(new Date()).toLocaleDateString()}.csv`,
);

export const downloadFacilitiesCSV = facilities =>
DownloadCSV(createFacilitiesCSV(facilities), 'facilities.csv');

export const makeUserLoginURL = () => '/user-login/';
export const makeUserLogoutURL = () => '/user-logout/';
export const makeUserSignupURL = () => '/user-signup/';
Expand Down Expand Up @@ -339,3 +349,50 @@ export const makeResetPasswordEmailURL = () =>

export const makeResetPasswordConfirmURL = () =>
'/rest-auth/password/reset/confirm/';

export const joinDataIntoCSVString = data => data
.reduce((csvAccumulator, nextRow) => {
const joinedColumns = nextRow
.reduce((rowAccumulator, nextColumn) => {
if (isNumber(nextColumn)) {
return rowAccumulator.concat(nextColumn, ',');
}

return rowAccumulator.concat(
'' + '"' + replace(nextColumn, '"', '\"') + '"', // eslint-disable-line
',',
);
}, '');

return csvAccumulator.concat(
trimEnd(joinedColumns, ','),
'\n',
);
}, '');

export const caseInsensitiveIncludes = (target, test) =>
includes(lowerCase(target), lowerCase(test));

export const sortFacilitiesAlphabeticallyByName = data => data
.slice()
.sort((
{
properties: {
name: firstFacilityName,
},
},
{
properties: {
name: secondFacilityName,
},
},
) => {
const a = lowerCase(firstFacilityName);
const b = lowerCase(secondFacilityName);

if (a === b) {
return 0;
}

return (a < b) ? -1 : 1;
});
5 changes: 3 additions & 2 deletions src/app/src/util/util.listItemCSV.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import get from 'lodash/get';
import fill from 'lodash/fill';
import isEmpty from 'lodash/isEmpty';
import flow from 'lodash/flow';
import { unparse } from 'papaparse';

import { joinDataIntoCSVString } from './util';

import { facilityMatchStatusChoicesEnum } from './constants';

Expand Down Expand Up @@ -96,4 +97,4 @@ export const listItemReducer = (acc, next) => {

export const formatDataForCSV = listItems => listItems.reduce(listItemReducer, [csvHeaders]);

export const createListItemCSV = flow(formatDataForCSV, unparse);
export const createListItemCSV = flow(formatDataForCSV, data => joinDataIntoCSVString(data));
38 changes: 1 addition & 37 deletions src/app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3913,7 +3913,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"

commander@2, commander@^2.11.0, commander@^2.15.1, commander@^2.8.1:
commander@2, commander@^2.11.0, commander@^2.8.1:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
Expand Down Expand Up @@ -7299,17 +7299,6 @@ json-stringify-safe@~5.0.1:
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=

json2csv@4.1.6:
version "4.1.6"
resolved "https://registry.yarnpkg.com/json2csv/-/json2csv-4.1.6.tgz#d56b15d72a050b6902ee960232ffd66c18f3051a"
integrity sha512-pmitnvvuX9OC6lL6T6F0sl6NsoXG94xLHKnKwdRSEpASFd3xdKHvsksPpNFZtDULP0AwOA0MGKrm1I0c7Enaxg==
dependencies:
commander "^2.15.1"
jsonparse "^1.3.1"
lodash.clonedeep "^4.5.0"
lodash.get "^4.4.2"
lodash.set "^4.3.2"

json3@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
Expand Down Expand Up @@ -7347,11 +7336,6 @@ jsonlint-lines-primitives@~1.6.0:
JSV ">= 4.0.x"
nomnom ">= 1.5.x"

jsonparse@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=

jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
Expand Down Expand Up @@ -7620,11 +7604,6 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=

lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=

lodash.cond@^4.3.0:
version "4.5.2"
resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
Expand All @@ -7640,21 +7619,11 @@ lodash.defaults@^4.2.0:
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=

lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=

lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=

lodash.set@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=

lodash.template@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
Expand Down Expand Up @@ -8613,11 +8582,6 @@ pako@~1.0.5:
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.7.tgz#2473439021b57f1516c82f58be7275ad8ef1bb27"
integrity sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ==

papaparse@4.6.3:
version "4.6.3"
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.6.3.tgz#742e5eaaa97fa6c7e1358d2934d8f18f44aee781"
integrity sha512-LRq7BrHC2kHPBYSD50aKuw/B/dGcg29omyJbKWY3KsYUZU69RKwaBHu13jGmCYBtOc4odsLCrFyk6imfyNubJQ==

param-case@2.1.x:
version "2.1.1"
resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
Expand Down

0 comments on commit dae70dc

Please sign in to comment.