diff --git a/src/components/Settings/Positions.tsx b/src/components/Settings/Positions.tsx
new file mode 100644
index 0000000..6783335
--- /dev/null
+++ b/src/components/Settings/Positions.tsx
@@ -0,0 +1,413 @@
+import {
+ JSX,
+ Component,
+ For,
+ useContext,
+ startTransition,
+ Show,
+ splitProps,
+} from "solid-js";
+import { produce, unwrap } from "solid-js/store";
+import { autoAnimate } from "~/directives/autoAnimate";
+import { sortable } from "~/directives/sortable";
+import {
+ LocalStoreContext,
+ Position,
+ POSITION_TYPE_AGILE,
+ POSITION_TYPE_QUANTITY,
+ StoreContext,
+ UiStoreContext,
+} from "~/stores";
+import AddIcon from "~icons/carbon/add-filled";
+import DeleteIcon from "~icons/carbon/trash-can";
+import DragVerticalIcon from "~icons/carbon/drag-vertical";
+import PositionSettingsIcon from "~icons/carbon/settings-adjust";
+import { Checkbox, TextArea, TextInput } from "../Form";
+import { parseOptionalFloat } from "~/util";
+import { MarkdownHelpLabel } from "../Markdown";
+
+export const PositionsSettings: Component = () => {
+ const [state, setState] = useContext(StoreContext)!;
+ const [uiState, setUiState] = useContext(UiStoreContext)!;
+
+ autoAnimate;
+ sortable;
+
+ const AddPositionButton: Component<{ idx?: number }> = (props) => (
+
+ );
+
+ return (
+ <>
+
{
+ setState(
+ "positions",
+ produce((positions: any[]) => {
+ const oldIndex = evt.oldIndex;
+ const newIndex = evt.newIndex;
+ let item = positions[oldIndex];
+ positions.splice(oldIndex, 1);
+ positions.splice(newIndex, 0, unwrap(item));
+ })
+ );
+ },
+ }}
+ >
+
+ {(position, idx) => {
+ let nameInputRef: HTMLInputElement = undefined!;
+ let positionNumberInputRef: HTMLInputElement = undefined!;
+ let onEnterKeyClose: JSX.EventHandler<
+ HTMLInputElement,
+ KeyboardEvent
+ > = (e) => {
+ if (e.code !== "Enter") {
+ return;
+ }
+
+ setUiState("selectedPosition", undefined);
+ };
+
+ const AgileDropdown: Component<
+ { selected: number } & JSX.HTMLAttributes
+ > = (p) => {
+ const [props, rest] = splitProps(p, ["selected", "class"]);
+ return (
+
+ );
+ };
+
+ return (
+
+
+
+
+
+
+
{
+ await startTransition(function () {
+ setUiState("selectedPosition", position.id);
+ });
+ if (positionNumberInputRef) {
+ positionNumberInputRef.focus();
+ }
+ }}
+ >
+ {position.number || idx() + 1}
+
+
{
+ await startTransition(function () {
+ setUiState("selectedPosition", position.id);
+ });
+ if (nameInputRef) {
+ nameInputRef.focus();
+ }
+ }}
+ >
+ {position.name}
+
+
+
+
+
+
+
+
+
+
+
{
+ setState(
+ "positions",
+ idx(),
+ "itemPrice",
+ parseOptionalFloat(e.currentTarget.value)
+ );
+ }}
+ />
+
+
+
+ {
+ setState(
+ "positions",
+ idx(),
+ "name",
+ e.currentTarget.value
+ );
+ }}
+ />
+
+
+ {
+ setState(
+ "positions",
+ idx(),
+ "number",
+ e.currentTarget.value
+ );
+ }}
+ />
+
+
+
+ setState(
+ "positions",
+ idx(),
+ "fixedDiscountPrice",
+ parseOptionalFloat(e.currentTarget.value)
+ )
+ }
+ />
+
+
+ }
+ value={position.description}
+ onInput={(evt) =>
+ setState(
+ "positions",
+ idx(),
+ "description",
+ evt.currentTarget.value
+ )
+ }
+ />
+
+
+
+ setState(
+ "positions",
+ idx(),
+ "enabled",
+ e.currentTarget.checked
+ )
+ }
+ >
+ Position ist aktiv
+
+
+
+
+
+
+
+
+ );
+ }}
+
+
+
+ >
+ );
+};