diff --git a/.eslintrc.js b/.eslintrc.js index a87ad79..a37bcdd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,7 +4,7 @@ module.exports = { parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], root: true, - ignorePatterns: ['build'], + ignorePatterns: ['build', 'dist'], rules: { eqeqeq: ['error', 'always'], }, diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..0a1109a --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,25 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs + +name: Node.js CI + +on: + push: + branches: ['main'] + pull_request: + branches: ['main'] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 18.x + uses: actions/setup-node@v3 + with: + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + node-version: 18.x + cache: 'yarn' + - run: yarn --frozen-lockfile + - run: yarn lint diff --git a/.prettierignore b/.prettierignore index 0011dce..c310368 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ # Build products build +dist diff --git a/package.json b/package.json index 38a6c2e..1e3a5bd 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "serve:widget": "parcel serve ./src/*.html --dist-dir build", "cypress:open": "cypress open", "cypress:run": "cypress run", - "lint": "prettier --check . && eslint .", + "lint": "tsc --noEmit && prettier --check . && eslint .", "prepare": "husky install" }, "browserslist": { diff --git a/src/calculator-form.ts b/src/calculator-form.ts index d3c1661..e7cbcd2 100644 --- a/src/calculator-form.ts +++ b/src/calculator-form.ts @@ -1,5 +1,5 @@ import { html, css, nothing, TemplateResult } from 'lit'; -import { downIcon, questionIcon } from './icons'; +import { questionIcon } from './icons'; import { select, multiselect, selectStyles, OptionParam } from './select'; import { inputStyles } from './styles/input'; import './currency-input'; diff --git a/src/calculator.ts b/src/calculator.ts index 14e3e45..fec7649 100644 --- a/src/calculator.ts +++ b/src/calculator.ts @@ -12,7 +12,6 @@ import { } from './calculator-types'; import { CALCULATOR_FOOTER } from './calculator-footer'; import { fetchApi } from './api/fetch'; -import { NO_PROJECT } from './projects'; import { downIcon } from './icons'; const loadedTemplate = ( @@ -126,7 +125,7 @@ export class RewiringAmericaCalculator extends LitElement { tax_filing, household_size, }); - return await fetchApi( + return await fetchApi( this.apiKey, this.apiHost, '/api/v0/calculator', diff --git a/src/state-calculator.ts b/src/state-calculator.ts index b88b7df..55ade1a 100644 --- a/src/state-calculator.ts +++ b/src/state-calculator.ts @@ -23,6 +23,7 @@ import '@shoelace-style/shoelace/dist/components/spinner/spinner'; import { STATES } from './states'; import { authorityLogosStyles } from './authority-logos'; import { APIResponse, APIUtilitiesResponse } from './api/calculator-types-v1'; +import { SlSelect } from '@shoelace-style/shoelace'; const loadingTemplate = () => html`
@@ -146,10 +147,10 @@ export class RewiringAmericaStateCalculator extends LitElement { override async firstUpdated() { // Give the browser a chance to paint await new Promise(r => setTimeout(r, 0)); - const select = this.renderRoot.querySelector('sl-select'); + const select = this.renderRoot.querySelector('sl-select') as SlSelect; const combobox = this.renderRoot .querySelector('sl-select') - ?.renderRoot.querySelector('div.select__combobox'); + ?.renderRoot.querySelector('div.select__combobox') as HTMLElement; select?.addEventListener('keydown', event => { if (event.key === 'Tab' && select.open) { diff --git a/src/state-incentive-details.ts b/src/state-incentive-details.ts index 82dddef..100b576 100644 --- a/src/state-incentive-details.ts +++ b/src/state-incentive-details.ts @@ -445,10 +445,9 @@ export const stateIncentivesTemplate = ( ]), ) as Record; - const nonSelectedProjects = Object.entries(PROJECTS) - .filter(([project, _]) => !selectedProjects.includes(project as Project)) - .sort(([a], [b]) => shortLabel(a).localeCompare(shortLabel(b))) - .map(([project, _]) => project); + const nonSelectedProjects = (Object.keys(PROJECTS) as Project[]) + .filter(project => !selectedProjects.includes(project)) + .sort((a, b) => shortLabel(a).localeCompare(shortLabel(b))); // Only offer "other" tabs if there are incentives for that project. const otherTabs = ( @@ -462,22 +461,19 @@ export const stateIncentivesTemplate = ( .map(([project]) => project); const projectTab = - selectedProjectTab && - selectedProjects.includes(selectedProjectTab as Project) + selectedProjectTab && selectedProjects.includes(selectedProjectTab) ? selectedProjectTab : selectedProjects[0]; const otherTab = - selectedOtherTab && - nonSelectedProjects.includes(selectedOtherTab as Project) + selectedOtherTab && nonSelectedProjects.includes(selectedOtherTab) ? selectedOtherTab : nonSelectedProjects[0]; const selectedIncentives = incentivesByProject[projectTab] ?? []; - const selectedOtherIncentives = - incentivesByProject[otherTab as Project] ?? []; + const selectedOtherIncentives = incentivesByProject[otherTab] ?? []; const otherIncentivesLabel = - selectedIncentives.length == 0 + selectedIncentives.length === 0 ? 'Incentives available to you' : 'Other incentives available to you'; @@ -494,7 +490,7 @@ export const stateIncentivesTemplate = ( selectedOtherIncentives, otherTabs, // If a nonexistent tab is selected, pretend the first one is selected. - otherTab as Project, + otherTab, onOtherTabSelected, )} ${authorityLogosTemplate(response)}`;