Skip to content

Commit

Permalink
chore: Adds types with js-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
tif-calin committed Oct 14, 2024
1 parent 3c55d6c commit 30af262
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Originally developed by annaleigh, austin, clem, culi, daniella.
* `npm`

## technology
this ancient front-end was made with create-react-app. it does not utilize typescript but is moving towards type safety with js-docs which [is a full-featured alternative to typescript](https://github.com/sveltejs/kit/discussions/4429#discussioncomment-2423814) that runs on the same engine.
this ancient front-end was made with create-react-app. it does not utilize typescript but is moving towards type safety with js-docs which [is a full-featured alternative to typescript](https://github.com/sveltejs/kit/discussions/4429#discussioncomment-2423814) that runs on the same engine!

## setup
0. clone down (`git clone [email protected]:openbookbook/bookbook-web.git`) and `cd ./bookbook-web`
Expand Down
4 changes: 3 additions & 1 deletion src/pages/ballot/BallotPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import AdminPanel from './AdminPanel';
import ResultsPanel from './ResultsPanel';
import './BallotPage.css';

/** @typedef {{ match: import('react-router-dom').RouteComponentProps['match'] }} BallotPageProps */

/** @param {BallotPageProps} props */
const BallotPage = props => {
const {
loading, ballot,
Expand Down Expand Up @@ -49,7 +51,7 @@ const BallotPage = props => {
/>
</>}

{Boolean(ballot?.endDate)
{Boolean(ballot?.endDate)
? <>
<span className="panel-title">results</span>
<ResultsPanel
Expand Down
9 changes: 9 additions & 0 deletions src/pages/setup/PermissionsPanel.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import React from 'react';

/**
* @typedef {{
* setVoteCode: React.Dispatch<React.SetStateAction<string>>;
* }} PermissionsPanelProps
*/

/** @param {PermissionsPanelProps} props */
const PermissionsPanel = props => {
const {
setVoteCode,
enableVoteCodeInput,
setEnableVoteCodeInput
} = props;

/** @type {React.ChangeEventHandler<HTMLInputElement>} */
const handleTextChange = e => setVoteCode(e.target.value);

return (
Expand Down
2 changes: 1 addition & 1 deletion src/pages/setup/SuggestPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const SuggestPanel = props => {
/>

<ul className="book-display list-view">
{results.filter(
{(results || []).filter(
book => !suggestions.some(suggestion => suggestion.gbooks === book.googleId)
).map(book => (
<li className="search-result" key={book.googleId}>
Expand Down
4 changes: 3 additions & 1 deletion src/state/useBallot.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { addUser, getBallot, getSuggestions, getUsers, loginUser, updateBallot, updateUser as putUser, patchUser } from '../utils/backend-api';
import { addUser, getBallot, getSuggestions, getUsers, loginUser, updateBallot, patchUser } from '../utils/backend-api';
import { getBook } from '../utils/gbooks-api';
import { base62, relocateItemInArray, shuffleArray } from '../utils/utils';
import { rankedChoiceVote } from '../utils/voting-methods';
Expand All @@ -13,6 +13,7 @@ const updateUserVote = async user => {
return await patchUser(user, ['vote', user.vote]);
};

/** @param {string} idFromUrl */
const useBallot = idFromUrl => {
const [ballot, setBallot] = useState(null);
const [users, setUsers] = useState([]);
Expand Down Expand Up @@ -121,6 +122,7 @@ const useBallot = idFromUrl => {
setUsers(users.map(u => u.id === currentUser.id ? currentUser : u));
};

/** @param {number} oldIndex; @param {number} newIndex */
const handleRankingChange = (oldIndex, newIndex) => {
const newRanking = relocateItemInArray(currentRanking.map(c => c.id), oldIndex, newIndex);
setCurrentRanking(newRanking.map(id => currentRanking.find(c => c.id === id)));
Expand Down
6 changes: 5 additions & 1 deletion src/state/useGoogleBooks.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useCallback, useState } from 'react';
import { searchBooks } from '../utils/gbooks-api';

/** @typedef {import('../utils/gbooks-api').Book} Book */

const useGoogleBooks = () => {
const [results, setResults] = useState([]);
/** @type {ReturnType<typeof useState<Book[]>>} */
const [results, setResults] = useState();

/** @type {React.ChangeEventHandler<HTMLInputElement>} */
const handleSearch = useCallback(
async e => {
let query = e.target.value;
Expand Down
11 changes: 6 additions & 5 deletions src/state/useSetup.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useState } from 'react';
import { useHistory } from 'react-router';
import {
addBallot as postBallot,
addSuggestion as postSuggestion
import {
addBallot as postBallot,
addSuggestion as postSuggestion
} from '../utils/backend-api';
import { base62 } from '../utils/utils';

const useSetup = () => {
/** @type {[string, React.Dispatch<React.SetStateAction<string>>]} */
const [errorMessage, setErrorMessage] = useState('');
const [ballotName, setBallotName] = useState('');
const [adminCode, setAdminCode] = useState('');
Expand All @@ -17,11 +18,11 @@ const useSetup = () => {

const history = useHistory();

const addSuggestion = (suggestion, type = 'book') =>
const addSuggestion = (suggestion, _type = 'book') =>
setSuggestions([...suggestions, suggestion])
;

const deleteSuggestion = (val, key = 'gbooks') =>
const deleteSuggestion = (val, key = 'gbooks') =>
setSuggestions(suggestions.filter(s => s[key] !== val));
;

Expand Down
6 changes: 6 additions & 0 deletions src/utils/backend-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const URL = process.env.NODE_ENV === 'development'
: 'https://openbookbook.herokuapp.com'
;

/**
* @param {'get' | 'post' | 'put' | 'patch' | 'delete'} method
* @param {string} path
* @template Dto @param {Dto} [data]
*/
const req = async (method, path, data) => {
try {
return (data
Expand All @@ -16,6 +21,7 @@ const req = async (method, path, data) => {
return { error: err.message };
}
};
/** @param {string} path; @template T @param {T} data */
const postReq = async (path, data) => await req('post', path, data);
const getReq = async (path) => await req('get', path);
const putReq = async (path, data) => await req('put', path, data);
Expand Down
16 changes: 16 additions & 0 deletions src/utils/gbooks-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import request from 'superagent';

const GBOOKS_API = 'https://www.googleapis.com/books/v1/volumes';

/** @returns {Promise<Book[]>} */
async function searchBooks(query, printType = 'books') {
const response = await request
.get(GBOOKS_API)
Expand All @@ -20,6 +21,21 @@ async function getBook(gbooks) {
return mungeBook(response.body);
}

/**
* @typedef {{
* authors: string[];
* description: string;
* googleId: string;
* image: string;
* pageCount: number;
* price: number | undefined;
* subtitle: string;
* title: string;
* }} Book
*
* @param {Object} book
* @returns {Book}
*/
function mungeBook(book) {
return {
authors: book.volumeInfo.authors || [],
Expand Down
17 changes: 11 additions & 6 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export function getByProperty(arr, val, prop = 'id') {
// this is exactly like findById(arr, val) if the prop parameter isn't specified
return arr.filter(obj => obj[prop] === val)[0];
}

/**
* @template T @param {Array<T>} arr
* @param {number} oldIndex
* @param {number} newIndex
*/
export function relocateItemInArray(arr, oldIndex, newIndex) {
// Here's a much more complicated, but more memory efficient (faster) one I found online:
let i, tmp;
// @ts-ignore
oldIndex = parseInt(oldIndex, 10);
// @ts-ignore
newIndex = parseInt(newIndex, 10);

if (oldIndex !== newIndex && 0 <= oldIndex && oldIndex <= arr.length && 0 <= newIndex && newIndex <= arr.length) {
Expand All @@ -27,6 +29,7 @@ export function relocateItemInArray(arr, oldIndex, newIndex) {
return arr;
}

/** @template T @param {Array<T>} arr */
export function shuffleArray(arr) {
const array = [...arr];
for (let i = (array.length - 1); i > 0; i--) {
Expand All @@ -38,8 +41,9 @@ export function shuffleArray(arr) {

export const base62 = {
charset: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
/** @param {number} integer */
encode: integer => {
if (integer === 0) return 0;
if (integer === 0) return '0';

let s = [];
while (integer > 0) {
Expand All @@ -48,5 +52,6 @@ export const base62 = {
}
return s.join('');
},
/** @param {string} chars */
decode: chars => chars.split('').reverse().reduce((prev, curr, i) => prev + (base62.charset.indexOf(curr) * (62 ** i)), 0)
};

0 comments on commit 30af262

Please sign in to comment.