import { Dispatch, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Button, Classes, ControlGroup, FormGroup, H6, InputGroup, MenuItem } from "@blueprintjs/core"; import { Select, SelectProps } from "@blueprintjs/select"; import { Placement } from "@blueprintjs/popover2"; import { ErrorCallout } from "Components/Errors"; import { ZoteroAPI } from "@clients/zotero"; import { ArrayAction, useArrayReducer } from "@hooks"; import { CustomClasses } from "../../../constants"; import { analyzeUserRequests } from "../../../setup"; import { DataRequest, UserDataRequest, UserRequests } from "Types/extension"; import "./_index.sass"; type LibraryOption = { label: string, value: ZoteroAPI.LibraryTypeURI }; type LibrarySelectorProps = SelectProps; const librarySelectStaticProps: Partial & Pick = { itemRenderer: (item, itemProps) => { const { handleClick/*, modifiers: { active }*/ } = itemProps; return ; }, popoverProps: { canEscapeKeyClose: false, minimal: true, placement: "bottom-right" as Placement, popoverClassName: CustomClasses.POPOVER, targetProps: { title: "Select the type of library you want to use" } } }; const LIB_TYPE_OPTIONS: LibraryOption[] = [ { label: "User library", value: "users" }, { label: "Group library", value: "groups" } ]; type DataRequestFormProps = { inputRef?: RefObject, pos: number | "new", req: UserDataRequest, updateReq: (value: UserDataRequest) => void }; function DataRequestForm({ inputRef = undefined, pos, req, updateReq }: DataRequestFormProps){ const { apikey, library: { type, id }, name } = req; const changeHandlers = useMemo(() => { function updateTextProp(prop, event){ updateReq({ ...req, [prop]: event.target.value }); } function updateLibraryParams(op, val){ updateReq({ ...req, library: { ...req.library, [op]: val } }); } return { updateAPIKey: (event) => updateTextProp("apikey", event), updateLibraryType: (item) => updateLibraryParams("type", item.value), updateLibraryID: (event) => updateLibraryParams("id", event.target.value), updateName: (event) => updateTextProp("name", event) }; }, [req, updateReq]); return <> ; } const DEFAULT_REQ: UserDataRequest = { apikey: "", library: { type: "users", id: "" }, name: "" }; type NewRequestProps = { dispatch: Dispatch>, inputRef?: RefObject }; function NewRequest({ dispatch, inputRef }: NewRequestProps){ const [req, updateReq] = useState(DEFAULT_REQ); const addToReqList = useCallback(() => { dispatch({ type: "add", value: req }); updateReq(DEFAULT_REQ); }, [dispatch, req]); return
; } type RequestAction = | { type: "removeSelf" } | { type: "updateSelf", value: UserDataRequest }; type ExistingRequestProps = { dispatch: Dispatch, pos: number, req: UserDataRequest }; function ExistingRequest({ dispatch, pos, req }: ExistingRequestProps) { return
dispatch({ type: "updateSelf", value })} />
; } type RequestsEditorProps = { closeDialog: () => void, dataRequests: DataRequest[], updateRequests: (value: UserRequests) => void }; function RequestsEditor({ closeDialog, dataRequests = [], updateRequests }: RequestsEditorProps) { const [reqList, dispatch] = useArrayReducer(dataRequests); const [validationError, setValidationError] = useState(null); const newReqField = useRef(null); useEffect(() => { setValidationError(null); }, [reqList]); useEffect(() => { newReqField?.current?.focus(); }, []); const requestDispatch = useCallback((index, action) => { switch (action.type) { case "removeSelf": return dispatch({ type: "remove", index }); case "updateSelf": return dispatch({ type: "update", index, value: action.value }); default: return; } }, [dispatch]); const updateIfValid = useCallback(() => { try { const reqs = analyzeUserRequests(reqList); updateRequests(reqs); closeDialog(); } catch(e){ setValidationError(e); } }, [closeDialog, reqList, updateRequests]); return <>
{reqList.map((req, i) => requestDispatch(i, action)} />)}
Add a new request
{validationError && }
; } export default RequestsEditor;