// Copyright (c) 2020-2021 Drew Lemmy // This file is part of TenebraWeb 2 under AGPL-3.0. // Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt import { useState, useEffect, Dispatch, SetStateAction } from "react"; import { Modal, Form, Button, Select, Radio } from "antd"; import { useTFns } from "@utils/i18n"; import { LookupFilterOptionsBase } from "./table"; export interface SortConfig<FieldsT extends string> { sortKey: FieldsT; i18nKey: string; } export type SortOptions<FieldsT extends string> = SortConfig<FieldsT>[]; interface FormValues<FieldsT extends string> { orderBy: FieldsT; order: "ASC" | "DESC"; } interface Props<FieldsT extends string> { visible: boolean; setVisible: Dispatch<SetStateAction<boolean>>; sortOptions: SortOptions<FieldsT>; defaultOrderBy: FieldsT; defaultOrder: "ASC" | "DESC"; options: LookupFilterOptionsBase<FieldsT>; setOptions: (opts: LookupFilterOptionsBase<FieldsT>) => void; } export function SortModal<FieldsT extends string>({ visible, setVisible, sortOptions, defaultOrderBy, defaultOrder, options, setOptions }: Props<FieldsT>): JSX.Element { const { t, tStr } = useTFns("sortModal."); const [form] = Form.useForm<FormValues<FieldsT>>(); async function onSubmit() { const values = await form.validateFields(); console.log(values); setOptions({ ...options, orderBy: values.orderBy, order: values.order }); closeModal(); } function onReset() { setOptions({ ...options, orderBy: defaultOrderBy, order: defaultOrder }); closeModal(); } function closeModal() { form.resetFields(); setVisible(false); } // Update the form values if the table is sorted useEffect(() => { if (!form || !options) return; form.setFieldsValue({ orderBy: options.orderBy || defaultOrderBy, order: options.order || defaultOrder } as any); }, [form, options, defaultOrderBy, defaultOrder]); return <Modal visible={visible} title={tStr("title")} onCancel={closeModal} destroyOnClose footer={<> {/* Reset */} <Button onClick={onReset} style={{ float: "left" }}> {tStr("buttonReset")} </Button> {/* Cancel */} <Button onClick={closeModal}> {t("dialog.cancel")} </Button> {/* Submit */} <Button type="primary" onClick={onSubmit}> {t("dialog.ok")} </Button> </>} > <Form<FormValues<FieldsT>> form={form} initialValues={{ sortBy: options.orderBy, sortOrder: options.order }} onFinish={onSubmit} > {/* Sort by */} <Form.Item name="orderBy" label={tStr("sortBy")}> {/* Present each available sort option as a field */} <Select> {sortOptions.map(opt => ( <Select.Option key={opt.sortKey} value={opt.sortKey}> {tStr("options." + opt.i18nKey)} </Select.Option> ))} </Select> </Form.Item> {/* Sort order (ascending, descending) */} <Form.Item name="order" label={tStr("sortOrder")}> <Radio.Group buttonStyle="solid"> <Radio.Button value="ASC">{tStr("sortAscending")}</Radio.Button> <Radio.Button value="DESC">{tStr("sortDescending")}</Radio.Button> </Radio.Group> </Form.Item> </Form> </Modal>; } export type OpenSortModalFn = (() => void)[]; export type SetOpenSortModalFn = (fn: OpenSortModalFn | undefined) => void; export function useSortModal<FieldsT extends string>( sortOptions: SortOptions<FieldsT>, defaultOrderBy: FieldsT, defaultOrder: "ASC" | "DESC", options: LookupFilterOptionsBase<FieldsT>, setOptions: (opts: LookupFilterOptionsBase<FieldsT>) => void, setOpenSortModal?: SetOpenSortModalFn ): JSX.Element { const [visible, setVisible] = useState(false); useEffect(() => setOpenSortModal?.([() => setVisible(true)]), [setOpenSortModal]); return <SortModal visible={visible} setVisible={setVisible} sortOptions={sortOptions} defaultOrderBy={defaultOrderBy} defaultOrder={defaultOrder} options={options} setOptions={setOptions} />; }