-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: Allow adding fixed hosts when 'add all team members' is enabled… #2
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,12 +45,19 @@ export const CheckedTeamSelect = ({ | |
value = [], | ||
isRRWeightsEnabled, | ||
customClassNames, | ||
onClearAllClick, | ||
onOptionChange, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The props interface needs to be updated to include 'assignAllTeamMembers' and 'isFixed' props since they are being used in the implementation. 🔨 See the suggested fix@@ -45,12 +45,16 @@
value = [],
isRRWeightsEnabled,
customClassNames,
+ assignAllTeamMembers,
+ isFixed,
...props
}: Omit<Props<CheckedSelectOption, true>, "value" | "onChange"> & {
value?: readonly CheckedSelectOption[];
onChange: (value: readonly CheckedSelectOption[]) => void;
isRRWeightsEnabled?: boolean;
customClassNames?: CheckedTeamSelectCustomClassNames;
+ assignAllTeamMembers?: boolean;
+ isFixed?: boolean;
}) => {
const isPlatform = useIsPlatform();
const [priorityDialogOpen, setPriorityDialogOpen] = useState(false);
@@ -201,4 +205,4 @@
}
};
-export default CheckedTeamSelect;
+export default CheckedTeamSelect; |
||
assignAllTeamMembers, | ||
isFixed, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type definition uses 'onChange' but the implementation uses 'onOptionChange' - please update the type to use 'onOptionChange' for consistency. 🔨 See the suggested fix@@ -48,7 +48,7 @@
...props
}: Omit<Props<CheckedSelectOption, true>, "value" | "onChange"> & {
value?: readonly CheckedSelectOption[];
- onChange: (value: readonly CheckedSelectOption[]) => void;
+ onOptionChange: (value: readonly CheckedSelectOption[]) => void;
isRRWeightsEnabled?: boolean;
customClassNames?: CheckedTeamSelectCustomClassNames;
}) => {
@@ -149,7 +149,7 @@
<Icon
name="x"
- onClick={() => props.onChange(value.filter((item) => item.value !== option.value))}
+ onClick={() => props.onOptionChange(value.filter((item) => item.value !== option.value))}
className={classNames(
"my-auto ml-2 h-4 w-4",
customClassNames?.selectedHostList?.listItem?.removeButton
@@ -166,14 +166,14 @@
isOpenDialog={priorityDialogOpen}
setIsOpenDialog={setPriorityDialogOpen}
option={currentOption}
- onChange={props.onChange}
+ onChange={props.onOptionChange}
customClassNames={customClassNames?.priorityDialog}
/>
<WeightDialog
isOpenDialog={weightDialogOpen}
setIsOpenDialog={setWeightDialogOpen}
option={currentOption}
- onChange={props.onChange}
+ onChange={props.onOptionChange}
customClassNames={customClassNames?.weightDialog}
/>
</>
@@ -201,4 +201,4 @@
}
};
-export default CheckedTeamSelect;
+export default CheckedTeamSelect; |
||
...props | ||
}: Omit<Props<CheckedSelectOption, true>, "value" | "onChange"> & { | ||
}: Omit<Props<CheckedSelectOption, true>, "value"> & { | ||
value?: readonly CheckedSelectOption[]; | ||
onChange: (value: readonly CheckedSelectOption[]) => void; | ||
onOptionChange: (value: readonly CheckedSelectOption[]) => void; | ||
isRRWeightsEnabled?: boolean; | ||
customClassNames?: CheckedTeamSelectCustomClassNames; | ||
onClearAllClick?: () => void; | ||
assignAllTeamMembers?: boolean; | ||
isFixed?: boolean; | ||
}) => { | ||
const isPlatform = useIsPlatform(); | ||
const [priorityDialogOpen, setPriorityDialogOpen] = useState(false); | ||
|
@@ -72,6 +79,12 @@ export const CheckedTeamSelect = ({ | |
isMulti | ||
className={customClassNames?.hostsSelect?.select} | ||
innerClassNames={customClassNames?.hostsSelect?.innerClassNames} | ||
onChange={(newValue, { action }) => { | ||
onOptionChange(newValue); | ||
if (action === "clear" && onClearAllClick) { | ||
onClearAllClick(); | ||
} | ||
}} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a key prop to the Fragment wrapper or remove it if not needed, as React requires keys for proper list reconciliation. |
||
{...props} | ||
/> | ||
{/* This class name conditional looks a bit odd but it allows a seemless transition when using autoanimate | ||
|
@@ -149,7 +162,13 @@ export const CheckedTeamSelect = ({ | |
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The icon click handler still uses props.onChange but the prop has been renamed to onOptionChange. This should be updated for consistency. 🔨 See the suggested fix@@ -149,7 +149,7 @@
<Icon
name="x"
- onClick={() => props.onChange(value.filter((item) => item.value !== option.value))}
+ onClick={() => props.onOptionChange(value.filter((item) => item.value !== option.value))}
className={classNames(
"my-auto ml-2 h-4 w-4",
customClassNames?.selectedHostList?.listItem?.removeButton
@@ -166,14 +166,14 @@
isOpenDialog={priorityDialogOpen}
setIsOpenDialog={setPriorityDialogOpen}
option={currentOption}
- onChange={props.onChange}
+ onChange={props.onOptionChange}
customClassNames={customClassNames?.priorityDialog}
/>
<WeightDialog
isOpenDialog={weightDialogOpen}
setIsOpenDialog={setWeightDialogOpen}
option={currentOption}
- onChange={props.onChange}
+ onChange={props.onOptionChange}
customClassNames={customClassNames?.weightDialog}
/>
</>
@@ -201,4 +201,4 @@
}
};
-export default CheckedTeamSelect;
+export default CheckedTeamSelect; |
||
<Icon | ||
name="x" | ||
onClick={() => props.onChange(value.filter((item) => item.value !== option.value))} | ||
onClick={() => { | ||
let newOption: CheckedSelectOption[] = []; | ||
if (isFixed && assignAllTeamMembers) { | ||
newOption = [{ ...option, isFixed: false }]; | ||
} | ||
onOptionChange([...value.filter((item) => item.value !== option.value), ...newOption]); | ||
}} | ||
className={classNames( | ||
"my-auto ml-2 h-4 w-4", | ||
customClassNames?.selectedHostList?.listItem?.removeButton | ||
|
@@ -166,14 +185,14 @@ export const CheckedTeamSelect = ({ | |
isOpenDialog={priorityDialogOpen} | ||
setIsOpenDialog={setPriorityDialogOpen} | ||
option={currentOption} | ||
onChange={props.onChange} | ||
onChange={onOptionChange} | ||
customClassNames={customClassNames?.priorityDialog} | ||
/> | ||
<WeightDialog | ||
isOpenDialog={weightDialogOpen} | ||
setIsOpenDialog={setWeightDialogOpen} | ||
option={currentOption} | ||
onChange={props.onChange} | ||
onChange={onOptionChange} | ||
customClassNames={customClassNames?.weightDialog} | ||
/> | ||
</> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -148,10 +148,28 @@ const FixedHosts = ({ | |
const { t } = useLocale(); | ||
const { getValues, setValue } = useFormContext<FormValues>(); | ||
|
||
const hasActiveFixedHosts = isRoundRobinEvent && getValues("hosts").some((host) => host.isFixed); | ||
const currentHosts = getValues("hosts"); | ||
const hasActiveFixedHosts = isRoundRobinEvent && currentHosts.some((host) => host.isFixed); | ||
|
||
const [isDisabled, setIsDisabled] = useState(hasActiveFixedHosts); | ||
|
||
const setAllHostsAsRR = () => | ||
setValue( | ||
"hosts", | ||
teamMembers.map((teamMember) => { | ||
const host = currentHosts.find((host) => host.userId === parseInt(teamMember.value, 10)); | ||
return { | ||
isFixed: false, | ||
userId: parseInt(teamMember.value, 10), | ||
priority: host?.priority ?? 2, | ||
weight: host?.weight ?? 100, | ||
// if host was already added, retain scheduleId | ||
scheduleId: host?.scheduleId || teamMember.defaultScheduleId, | ||
}; | ||
}), | ||
{ shouldDirty: true } | ||
); | ||
|
||
return ( | ||
<div className={classNames("mt-5 rounded-lg", customClassNames?.container)}> | ||
{!isRoundRobinEvent ? ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setAllHostsAsRR function doesn't preserve fixed host status when assignAllTeamMembers is true. This could cause fixed hosts to unexpectedly become RR hosts. 🔨 See the suggested fix@@ -353,38 +353,38 @@
/>
</>
)}
- <AddMembersWithSwitch
- teamId={teamId}
- teamMembers={teamMembers}
- value={value}
- onChange={onChange}
- assignAllTeamMembers={assignAllTeamMembers}
- setAssignAllTeamMembers={setAssignAllTeamMembers}
- isSegmentApplicable={isSegmentApplicable}
- automaticAddAllEnabled={true}
- isRRWeightsEnabled={isRRWeightsEnabled}
- isFixed={false}
- containerClassName={assignAllTeamMembers ? "-mt-4" : ""}
- onActive={() => {
- const currentHosts = getValues("hosts");
- setValue(
- "hosts",
- teamMembers.map((teamMember) => {
- const host = currentHosts.find((host) => host.userId === parseInt(teamMember.value, 10));
- return {
- isFixed: false,
- userId: parseInt(teamMember.value, 10),
- priority: host?.priority ?? 2,
- weight: host?.weight ?? 100,
- // if host was already added, retain scheduleId
- scheduleId: host?.scheduleId || teamMember.defaultScheduleId,
- };
- }),
- { shouldDirty: true }
- );
- }}
- customClassNames={customClassNames?.addMembers}
- />
+ <AddMembersWithSwitch
+ teamId={teamId}
+ teamMembers={teamMembers}
+ value={value}
+ onChange={onChange}
+ assignAllTeamMembers={assignAllTeamMembers}
+ setAssignAllTeamMembers={setAssignAllTeamMembers}
+ isSegmentApplicable={isSegmentApplicable}
+ automaticAddAllEnabled={true}
+ isRRWeightsEnabled={isRRWeightsEnabled}
+ isFixed={false}
+ containerClassName={assignAllTeamMembers ? "-mt-4" : ""}
+ onActive={() => {
+ const currentHosts = getValues("hosts");
+ setValue(
+ "hosts",
+ teamMembers.map((teamMember) => {
+ const host = currentHosts.find((host) => host.userId === parseInt(teamMember.value, 10));
+ return {
+ isFixed: host?.isFixed ?? false,
+ userId: parseInt(teamMember.value, 10),
+ priority: host?.priority ?? 2,
+ weight: host?.weight ?? 100,
+ // if host was already added, retain scheduleId
+ scheduleId: host?.scheduleId || teamMember.defaultScheduleId,
+ };
+ }),
+ { shouldDirty: true }
+ );
+ }}
+ customClassNames={customClassNames?.addMembers}
+ />
</div>
</div>
);
|
||
|
@@ -216,6 +234,9 @@ const FixedHosts = ({ | |
switchContainerClassName={customClassNames?.container} | ||
onCheckedChange={(checked) => { | ||
if (!checked) { | ||
if (assignAllTeamMembers) { | ||
setAllHostsAsRR(); | ||
} | ||
const rrHosts = getValues("hosts") | ||
.filter((host) => !host.isFixed) | ||
.sort((a, b) => (b.priority ?? 2) - (a.priority ?? 2)); | ||
|
@@ -236,6 +257,7 @@ const FixedHosts = ({ | |
setAssignAllTeamMembers={setAssignAllTeamMembers} | ||
automaticAddAllEnabled={!isRoundRobinEvent} | ||
isFixed={true} | ||
onClearAllClick={() => setAllHostsAsRR()} | ||
onActive={() => { | ||
const currentHosts = getValues("hosts"); | ||
setValue( | ||
|
@@ -531,7 +553,14 @@ const Hosts = ({ | |
teamMembers={teamMembers} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add duplicate checking between fixed and non-fixed hosts using Set or array filtering to prevent the same host from appearing in both pools based on userId. 🔨 See the suggested fix@@ -354,19 +354,26 @@
</>
)}
<AddMembersWithSwitch
- teamId={teamId}
- teamMembers={teamMembers}
- value={value}
- onChange={onChange}
- assignAllTeamMembers={assignAllTeamMembers}
- setAssignAllTeamMembers={setAssignAllTeamMembers}
- isSegmentApplicable={isSegmentApplicable}
- automaticAddAllEnabled={true}
- isRRWeightsEnabled={isRRWeightsEnabled}
- isFixed={false}
- containerClassName={assignAllTeamMembers ? "-mt-4" : ""}
- onActive={() => {
- const currentHosts = getValues("hosts");
+ teamId={teamId}
+ teamMembers={teamMembers}
+ value={value}
+ onChange={onChange}
+ assignAllTeamMembers={assignAllTeamMembers}
+ setAssignAllTeamMembers={setAssignAllTeamMembers}
+ isSegmentApplicable={isSegmentApplicable}
+ automaticAddAllEnabled={true}
+ isRRWeightsEnabled={isRRWeightsEnabled}
+ isFixed={false}
+ containerClassName={assignAllTeamMembers ? "-mt-4" : ""}
+ onActive={() => {
+ const currentHosts = getValues("hosts");
+ const nonFixedTeamMembers = teamMembers.filter((member) => {
+ const fixedHostUserIds = currentHosts.filter((h) => h.isFixed).map((h) => h.userId);
+ return !fixedHostUserIds.includes(parseInt(member.value, 10));
+ });
+ setValue(
+ "hosts",
+ nonFixedTeamMembers.map((teamMember) => {
setValue(
"hosts",
teamMembers.map((teamMember) => {
@@ -534,27 +541,31 @@
onChange([...value.filter((host: Host) => !host.isFixed), ...updatedHosts(changeValue)]);
}}
assignAllTeamMembers={assignAllTeamMembers}
- setAssignAllTeamMembers={setAssignAllTeamMembers}
- isRoundRobinEvent={true}
- customClassNames={customClassNames?.fixedHosts}
- />
- <RoundRobinHosts
- orgId={orgId}
- teamId={teamId}
- teamMembers={teamMembers}
- value={value}
- onChange={(changeValue) => {
- const hosts = [...value.filter((host: Host) => host.isFixed), ...updatedHosts(changeValue)];
- onChange(hosts);
- }}
- assignAllTeamMembers={assignAllTeamMembers}
- setAssignAllTeamMembers={setAssignAllTeamMembers}
- customClassNames={customClassNames?.roundRobinHosts}
- isSegmentApplicable={isSegmentApplicable}
- />
- </>
- ),
- MANAGED: <></>,
+ setAssignAllTeamMembers={setAssignAllTeamMembers}
+ isRoundRobinEvent={true}
+ customClassNames={customClassNames?.fixedHosts}
+ />
+ <RoundRobinHosts
+ orgId={orgId}
+ teamId={teamId}
+ teamMembers={teamMembers.filter((member) => {
+ // Filter out members that are already fixed hosts
+ const fixedHostUserIds = value.filter((h) => h.isFixed).map((h) => h.userId);
+ return !fixedHostUserIds.includes(parseInt(member.value, 10));
+ })}
+ value={value}
+ onChange={(changeValue) => {
+ const hosts = [...value.filter((host: Host) => host.isFixed), ...updatedHosts(changeValue)];
+ onChange(hosts);
+ }}
+ assignAllTeamMembers={assignAllTeamMembers}
+ setAssignAllTeamMembers={setAssignAllTeamMembers}
+ customClassNames={customClassNames?.roundRobinHosts}
+ isSegmentApplicable={isSegmentApplicable}
+ />
+ </>
+ ),
+ MANAGED: <></>,
};
return !!schedulingType ? schedulingTypeRender[schedulingType] : <></>;
}}
|
||
value={value} | ||
onChange={(changeValue) => { | ||
onChange([...value.filter((host: Host) => !host.isFixed), ...updatedHosts(changeValue)]); | ||
onChange([ | ||
...value.filter( | ||
(host: Host) => | ||
!host.isFixed && | ||
!changeValue.some((changedHost) => changedHost.userId === host.userId) | ||
), | ||
...updatedHosts(changeValue), | ||
]); | ||
}} | ||
assignAllTeamMembers={assignAllTeamMembers} | ||
setAssignAllTeamMembers={setAssignAllTeamMembers} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using consistent prop names: 'onChange' in CheckedHostField should match 'onOptionChange' used in CheckedTeamSelect.
🔨 See the suggested fix