Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix pinMapping dropdown layout issues #685

Merged
merged 1 commit into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion www/src/Pages/KeyboardMapping.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { AppContext } from '../Contexts/AppContext';
import KeyboardMapper, { validateMappings } from '../Components/KeyboardMapper';
import Section from '../Components/Section';
import WebApi, { baseButtonMappings } from '../Services/WebApi';
import './PinMappings.scss';

export default function KeyboardMappingPage() {
const { buttonLabels } = useContext(AppContext);
Expand Down
93 changes: 58 additions & 35 deletions www/src/Pages/PinMapping.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import React, { useCallback, useContext, useEffect, useState } from 'react';
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
import Select from 'react-select';
import { NavLink } from 'react-router-dom';
import { Alert, Button, Form, Tab, Tabs } from 'react-bootstrap';
import { Trans, useTranslation } from 'react-i18next';
import invert from 'lodash/invert';
import map from 'lodash/map';
import omit from 'lodash/omit';
import zip from 'lodash/zip';

import { AppContext } from '../Contexts/AppContext';
import Section from '../Components/Section';
import usePinStore from '../Store/usePinStore';

import './PinMappings.scss';
import CaptureButton from '../Components/CaptureButton';
import { getButtonLabels } from '../Data/Buttons';
import {
Expand All @@ -21,6 +26,10 @@ import {
} from '../Data/Pins';
import useProfilesStore from '../Store/useProfilesStore';

type PinCell = [string, PinActionValues];
type PinRow = [PinCell, PinCell];
type PinList = [PinRow];

const isNonSelectable = (value) =>
NON_SELECTABLE_BUTTON_ACTIONS.includes(value);

Expand Down Expand Up @@ -63,6 +72,47 @@ const PinsForm = ({ savePins, pins, setPinAction }: PinsFormTypes) => {
}
};

const pinList = useMemo<PinList>(() => {
const pinArray = Object.entries(pins);
return zip(
pinArray.slice(0, pinArray.length / 2),
pinArray.slice(pinArray.length / 2, pinArray.length),
);
}, [pins]);

const createCell = useCallback(
([pin, pinAction]: PinCell) => (
<div className="d-flex col py-2">
<div className="d-flex align-items-center" style={{ width: '4rem' }}>
<label htmlFor={pin}>{pin.toUpperCase()}</label>
</div>
<Select
inputId={pin}
className="text-primary flex-grow-1"
isClearable
isSearchable
options={options}
value={getOption(pinAction)}
isDisabled={isNonSelectable(pinAction)}
getOptionLabel={(option) => {
const labelKey = option.label.split('BUTTON_PRESS_').pop();
// Need to fallback as some button actions are not part of button names
return (
buttonNames[labelKey] || t(`PinMapping:actions.${option.label}`)
);
}}
onChange={(change) =>
setPinAction(
pin,
change?.value === undefined ? -10 : change.value, // On clear set to -10
)
}
/>
</div>
),
[],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options technically is a dependency but there are no practical differences since it is a const

Copy link
Contributor Author

@Pelsin Pelsin Dec 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking the pr out!

I believe that options is not a dependency needing to declare as it's not a reactive value, it's defined outside of the component

This is even matching an exact example from the new react docs on how to use dependency array with non reactive value:

const serverUrl = 'https://localhost:1234';
const roomId = 'general';

function ChatRoom() {
  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, []); // ✅ All dependencies declared
  // ...
}

Source: https://react.dev/learn/lifecycle-of-reactive-effects#what-an-effect-with-empty-dependencies-means

);

return (
<Form onSubmit={handleSubmit}>
<div className="py-3">
Expand All @@ -80,38 +130,11 @@ const PinsForm = ({ savePins, pins, setPinAction }: PinsFormTypes) => {
}
/>
</div>
<div className="gx-3 column-container">
{map(pins, (pinAction, pin) => (
<div key={`pin-${pin}`} className="d-flex py-2">
<div
className="d-flex align-items-center"
style={{ width: '4rem' }}
>
<label htmlFor={pin}>{pin.toUpperCase()}</label>
</div>
<Select
inputId={pin}
className="text-primary flex-grow-1"
isClearable
isSearchable
options={options}
value={getOption(pinAction)}
isDisabled={isNonSelectable(pinAction)}
getOptionLabel={(option) => {
const labelKey = option.label.split('BUTTON_PRESS_').pop();
// Need to fallback as some button actions are not part of button names
return (
buttonNames[labelKey] ||
t(`PinMapping:actions.${option.label}`)
);
}}
onChange={(change) =>
setPinAction(
pin,
change?.value === undefined ? -10 : change.value, // On clear set to -10
)
}
/>
<div className="gx-3">
{pinList.map(([cell1, cell2], i) => (
<div key={`pin-row-${i}`} className="row">
{createCell(cell1)}
{createCell(cell2)}
</div>
))}
</div>
Expand Down
4 changes: 0 additions & 4 deletions www/src/Pages/PinMappings.scss

This file was deleted.