diff --git a/client/package-lock.json b/client/package-lock.json index 714153a9..28ceba6c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -23,7 +23,7 @@ "eslint-plugin-vue": "^9.20.1", "happy-dom": "^13.1.4", "jest-serializer-vue-tjw": "^3.20.0", - "pdap-design-system": "^2.3.0", + "pdap-design-system": "^2.5.0", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "vite": "^4.5.1", @@ -3950,9 +3950,9 @@ } }, "node_modules/pdap-design-system": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pdap-design-system/-/pdap-design-system-2.3.0.tgz", - "integrity": "sha512-wTYw/kSrQ39f8u5Z66C37kMmlKZDSm1jtY4LswIGWpWx40xh6rt2MRj5d4A0PxCIm9ftRzLqmxQ4ykfh0Th49A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pdap-design-system/-/pdap-design-system-2.5.0.tgz", + "integrity": "sha512-5a9oWn6V/G51YfIVsepV1HN4OFSVWiALC1EWcmB6K4FyMdt6yhu/jM+jV9SFj4q0KQNbfUCzDVLD1ltGaDODKw==", "dev": true, "dependencies": { "@vuelidate/core": "^2.0.3", diff --git a/client/package.json b/client/package.json index a2504e2f..597846eb 100644 --- a/client/package.json +++ b/client/package.json @@ -29,7 +29,7 @@ "eslint-plugin-vue": "^9.20.1", "happy-dom": "^13.1.4", "jest-serializer-vue-tjw": "^3.20.0", - "pdap-design-system": "^2.3.0", + "pdap-design-system": "^2.5.0", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "vite": "^4.5.1", @@ -42,4 +42,4 @@ "not dead", "not ie 11" ] -} +} \ No newline at end of file diff --git a/client/src/components/SearchResultCard.vue b/client/src/components/SearchResultCard.vue index 6e2e245a..d662c30e 100644 --- a/client/src/components/SearchResultCard.vue +++ b/client/src/components/SearchResultCard.vue @@ -3,9 +3,32 @@ class="flex flex-col border border-neutral-400 p-3 text-lg leading-snug" data-test="search-result-card" > -

+

{{ dataSource.data_source_name }} -

+ + + +

{{ dataSource.record_type }}
-

- Unknown -

+

Unknown

- Agency -

+ Agency +

{{ dataSource.agency_name }}

Unknown

-

Time range

2016–2017

-

Formats available

+

Formats available

-
- - -
+ `; exports[`SearchResultCard with coverage end but not start > search result card exists with coverage end but not start 1`] = `
-

+

+

Record type

-

Unknown

+

Unknown

Agency

Unknown

@@ -82,21 +82,19 @@ exports[`SearchResultCard with coverage end but not start > search result card e -->

Time range

Unknown start–2016

-

Formats available

-

Unknown

-
- - -
+

Formats available

+

Unknown

+
`; exports[`SearchResultCard with coverage start but not end > search result card exists with coverage start but not end 1`] = `
-

+

+

Record type

-

Unknown

+

Unknown

Agency

Unknown

@@ -120,21 +118,19 @@ exports[`SearchResultCard with coverage start but not end > search result card e -->

Time range

2016–Unknown end

-

Formats available

-

Unknown

-
- - -
+

Formats available

+

Unknown

+
`; exports[`SearchResultCard with missing data > search result card exists with missing data 1`] = `
-

Calls for Service for Cicero Police Department - IN

+

Calls for Service for Cicero Police Department - IN

+

Record type

-

Unknown

+

Unknown

Agency

Unknown

@@ -157,13 +153,9 @@ exports[`SearchResultCard with missing data > search result card exists with mis
-->

Time range

-

Unknown

-

Formats available

-

Unknown

-
- - -
+

Unknown

+

Formats available

+

Unknown

+
`; diff --git a/client/src/pages/DataSourceStaticView.vue b/client/src/pages/DataSourceStaticView.vue index a38118bf..cfa94b5f 100644 --- a/client/src/pages/DataSourceStaticView.vue +++ b/client/src/pages/DataSourceStaticView.vue @@ -130,7 +130,7 @@ import axios from 'axios'; import { Button } from 'pdap-design-system'; import formatDateForSearchResults from '../util/formatDate'; -import { STATIC_VIEW_UI_SHAPE } from './util'; +import { STATIC_VIEW_UI_SHAPE } from '../util/pageData.js'; export default { name: 'DataSourceStaticView', @@ -198,3 +198,4 @@ export default { @apply my-2; } +./pageData diff --git a/client/src/pages/SearchResultPage.vue b/client/src/pages/SearchResultPage.vue index a13a7976..33c6ed2d 100644 --- a/client/src/pages/SearchResultPage.vue +++ b/client/src/pages/SearchResultPage.vue @@ -5,9 +5,7 @@

Searching for "{{ searchTerm }}" in "{{ location }}". - Found {{ getResultsCopy() }}.

@@ -16,56 +14,55 @@ New search
- - - Loading results... - - -

- If you don't see what you need, - - make a request  - -

-

- To see these results in a table, - - view the full database  - -

-
- + Loading results... +

+ +

+ No results found. +

+ +
+

+ If you don't see what you need, + + make a request  + +

+

+ To see these results in a table, + + view the full database  + +

+
+ +
+ - No results found. - - - + + {{ section.header }} + + + + +
@@ -74,6 +71,7 @@ import { Button, GridContainer, GridItem } from 'pdap-design-system'; import SearchResultCard from '../components/SearchResultCard.vue'; import axios from 'axios'; import pluralize from '../util/pluralize'; +import { SEARCH_RESULTS_UI_SHAPE } from '../util/pageData'; export default { name: 'SearchResultPage', @@ -84,11 +82,12 @@ export default { GridItem, }, data: () => ({ + count: 0, searched: false, - searchStatusCode: 200, searchResult: {}, searchTerm: '', location: '', + uiShape: {}, }), mounted: function () { this.searchTerm = this.$route.params.searchTerm; @@ -97,8 +96,7 @@ export default { }, methods: { getResultsCopy() { - const count = this.searchResult?.data?.length; - return `${count} ${pluralize('result', count)}`; + return `${this.count} ${pluralize('result', this.count)}`; }, async search() { const url = `${ @@ -109,11 +107,26 @@ export default { try { const res = await axios.get(url); - this.searchStatusCode = res.status; - this.searchResult = res.data; + + // Format results into object keyed by record_type + const resultFormatted = res.data.data.reduce((acc, cur) => { + return { ...acc, [cur.record_type]: cur }; + }, {}); + + // Modify ui shape object to exclude any sections / data sources that do not have records returned by API + this.uiShape = SEARCH_RESULTS_UI_SHAPE.reduce((acc, cur) => { + const recordsFiltered = cur.records.filter( + (record) => resultFormatted[record.type], + ); + return recordsFiltered.length > 0 + ? [...acc, { header: cur.header, records: recordsFiltered }] + : acc; + }, []); + + // Set data and away we go + this.searchResult = resultFormatted; + this.count = Object.entries(this.searchResult).length; } catch (error) { - this.searchStatusCode = error?.response?.status ?? 400; - this.searchResult = error?.response?.data ?? {}; console.error(error); } finally { this.searched = true; @@ -122,3 +135,9 @@ export default { }, }; + + diff --git a/client/src/pages/__tests__/__snapshots__/quickSearchPage.test.js.snap b/client/src/pages/__tests__/__snapshots__/quickSearchPage.test.js.snap index 91dd5e6c..124597ed 100644 --- a/client/src/pages/__tests__/__snapshots__/quickSearchPage.test.js.snap +++ b/client/src/pages/__tests__/__snapshots__/quickSearchPage.test.js.snap @@ -2,26 +2,6 @@ exports[`QuickSearchPage > is a Vue instance 1`] = `
-
-

Search our database

-

If you have a question to answer, we may already know about helpful data in your area. Learn more about the data here. -

-
-
-
- -
- - - -
-
- - - -
- -
-
+
`; diff --git a/client/src/pages/__tests__/__snapshots__/searchResultPage.test.js.snap b/client/src/pages/__tests__/__snapshots__/searchResultPage.test.js.snap index e6cf0c9c..b0190c24 100644 --- a/client/src/pages/__tests__/__snapshots__/searchResultPage.test.js.snap +++ b/client/src/pages/__tests__/__snapshots__/searchResultPage.test.js.snap @@ -4,106 +4,34 @@ exports[`SearchResultPage renders with data > Calls API and renders search resul

Data Sources Search results

-

Searching for "calls" in "Cook". Found 3 results. +

Searching for "calls" in "Cook". Found 1 result.

-
-
-

If you don't see what you need, make a request  - -

-

To see these results in a table, view the full database  - -

-
-
-

Calls for Service for Cicero Police Department - IN

-

Record type

-
Calls for Service
-
-

Agency

-

Cicero Police Department - IN

-
- -

Time range

-

2016–Unknown end

-

Formats available

-
    -
  • [
  • -
  • ]
  • -
-
- - -
-
-
-

Calls for Service for Chicago Police Department - IL

-

Record type

-
Calls for Service
-
-

Agency

-

Chicago Police Department - IL

-
- -

Time range

-

2018–Unknown end

-

Formats available

-
    -
  • [
  • -
  • ]
  • -
-
+
+

If you don't see what you need, make a request  + +

+

To see these results in a table, view the full database  + +

+
+
+
+

Police & public interactions

+
+

311 Calls for City of Chicago

- -
-
-
-

311 Calls for City of Chicago

-

Record type

-
Calls for Service
-
-

Agency

-

Chicago Police Department - IL

-
- -

Time range

-

12/17/2018–Unknown end

-

Formats available

-
    -
  • [
  • -
  • '
  • -
  • C
  • -
  • S
  • -
  • V
  • -
  • '
  • -
  • ,
  • -
  • -
  • '
  • -
  • X
  • -
  • M
  • -
  • L
  • -
  • '
  • -
  • ,
  • -
  • -
  • '
  • -
  • R
  • -
  • D
  • -
  • F
  • -
  • '
  • -
  • ,
  • -
  • -
  • '
  • -
  • R
  • -
  • S
  • -
  • S
  • -
  • '
  • -
  • ]
  • -
-
- - +

Time range

+

12/17/2018–Unknown end

+

Formats available

+
    +
  • [
  • +
  • '
  • +
  • C
  • +
  • S
  • +
  • V
  • +
  • '
  • +
  • ,
  • +
  • +
  • '
  • +
  • X
  • +
  • M
  • +
  • L
  • +
  • '
  • +
  • ,
  • +
  • +
  • '
  • +
  • R
  • +
  • D
  • +
  • F
  • +
  • '
  • +
  • ,
  • +
  • +
  • '
  • +
  • R
  • +
  • S
  • +
  • S
  • +
  • '
  • +
  • ]
  • +
+
-
-
+ +
`; diff --git a/client/src/pages/__tests__/quickSearchPage.test.js b/client/src/pages/__tests__/quickSearchPage.test.js index e447c0bb..bf2c2c5b 100644 --- a/client/src/pages/__tests__/quickSearchPage.test.js +++ b/client/src/pages/__tests__/quickSearchPage.test.js @@ -1,11 +1,14 @@ -import { mount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import QuickSearchPage from '../QuickSearchPage.vue'; import { describe, expect, test } from 'vitest'; describe('QuickSearchPage', () => { test('is a Vue instance', () => { - const wrapper = mount(QuickSearchPage); + const wrapper = shallowMount(QuickSearchPage); expect(wrapper.vm).toBeTruthy(); expect(wrapper.html()).toMatchSnapshot(); }); }); + +// Shallow mounting this test for now. It's 1. not really testing much, and 2. erroring on `getRoutes` +// TODO: write an actual test for this. diff --git a/client/src/pages/__tests__/searchResultPage.test.js b/client/src/pages/__tests__/searchResultPage.test.js index 38a9653f..c24ac9e6 100644 --- a/client/src/pages/__tests__/searchResultPage.test.js +++ b/client/src/pages/__tests__/searchResultPage.test.js @@ -69,18 +69,15 @@ describe('SearchResultPage renders with data', () => { const searchTerm = wrapper.vm.searchTerm; const location = wrapper.vm.location; - const count = wrapper.vm.searchResult.count; expect( wrapper.get('[data-test="search-results-section-header-p"]').text(), ).toBe( - `Searching for "${searchTerm}" in "${location}". Found ${count} results.`, + `Searching for "${searchTerm}" in "${location}". Found ${wrapper.vm.getResultsCopy()}.`, ); }); test('renders search result count properly', () => { - // const count = wrapper.vm.searchResult.count; - expect(wrapper.get('[data-test="search-results-count"]').text()).toBe( `Found ${wrapper.vm.getResultsCopy()}.`, ); @@ -95,7 +92,7 @@ describe('SearchResultPage renders with data', () => { test('search results card count matches search results returned in data', () => { expect(wrapper.findAll('[data-test="search-results-cards"]').length).toBe( - wrapper.vm.searchResult.count, + wrapper.vm.count, ); }); }); diff --git a/client/src/pages/util.js b/client/src/util/pageData.js similarity index 69% rename from client/src/pages/util.js rename to client/src/util/pageData.js index 983632c7..01bb8946 100644 --- a/client/src/pages/util.js +++ b/client/src/util/pageData.js @@ -122,3 +122,65 @@ export const STATIC_VIEW_UI_SHAPE = [ ], }, ]; + +export const SEARCH_RESULTS_UI_SHAPE = [ + { + header: 'Police & public interactions', + records: [ + { type: 'Accident Reports' }, + { type: 'Arrest Records' }, + { type: 'Calls for Service' }, + { type: 'Car GPS' }, + { type: 'Citations' }, + { type: 'Dispatch Logs' }, + { type: 'Dispatch Recordings' }, + { type: 'Field Contacts' }, + { type: 'Incident Reports' }, + { type: 'Misc Police Activity' }, + { type: 'Officer Involved Shootings' }, + { type: 'Stops' }, + { type: 'Surveys' }, + { type: 'Use of Force Reports' }, + { type: 'Vehicle Pursuits' }, + ], + }, + { + header: 'Info about officers', + records: [ + { type: 'Complaints & Misconduct' }, + { type: 'Daily Activity Logs' }, + { type: 'Training & Hiring Info' }, + { type: 'Personnel Records' }, + ], + }, + { + header: 'Info about agencies', + records: [ + { type: 'Annual & Monthly Reports' }, + { type: 'Budgets & Finances' }, + { type: 'Contact Info & Agency Meta' }, + { type: 'Geographic' }, + { type: 'List of Data Sources' }, + { type: 'Policies & Contracts' }, + ], + }, + { + header: 'Agency-published resources', + records: [ + { type: 'Crime Maps & Reports' }, + { type: 'Crime Statistics' }, + { type: 'Records Request Info' }, + { type: 'Resources' }, + { type: 'Sex Offender Registry' }, + { type: 'Wanted Persons' }, + ], + }, + { + header: 'Jails & Courts specific', + records: [ + { type: 'Booking Reports' }, + { type: 'Court Cases' }, + { type: 'Incarceration Records' }, + ], + }, +]; diff --git a/client/vite.config.js b/client/vite.config.js index 55ca83a7..d5972fed 100644 --- a/client/vite.config.js +++ b/client/vite.config.js @@ -1,25 +1,28 @@ -import { defineConfig } from "vite"; -import vue from "@vitejs/plugin-vue"; -import svgLoader from "vite-svg-loader"; +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import svgLoader from 'vite-svg-loader'; export default defineConfig({ - plugins: [vue(), svgLoader({ defaultImport: "url" })], + plugins: [vue(), svgLoader({ defaultImport: 'url' })], resolve: { paths: { - "@/*": ["src/*"], + '@/*': ['src/*'], }, }, + server: { + port: 8888, + }, test: { coverage: { all: true, - include: ["src/**/*.vue", "src/util/**/*.js"], - provider: "v8", - reportsDirectory: "./coverage", + include: ['src/**/*.vue', 'src/util/**/*.js'], + provider: 'v8', + reportsDirectory: './coverage', }, - environment: "happy-dom", - exclude: ["node_modules"], + environment: 'happy-dom', + exclude: ['node_modules'], globals: true, - include: ["src/**/{__tests__,__spec__}/*.test.js"], - setupFiles: ["tools/testing/setup.js"], + include: ['src/**/{__tests__,__spec__}/*.test.js'], + setupFiles: ['tools/testing/setup.js'], }, });