-
-
- {intl.formatMessage(intlMessages.optionsTitle)}
-
-
-
- {
- setFilterOptions((filterOptionsPrevious) => ({
- ...filterOptionsPrevious,
- includeModerators: !filterOptionsPrevious.includeModerators,
- }));
- }}
- name="options"
- value="includeModerators"
- />
-
- {intl.formatMessage(intlMessages.includeModeratorsLabel)}
-
-
-
- {
- setFilterOptions((filterOptionsPrevious) => ({
- ...filterOptionsPrevious,
- includePresenter: !filterOptionsPrevious.includePresenter,
- }));
- }}
- name="options"
- value="includePresenter"
- />
-
- {intl.formatMessage(intlMessages.includePresenterLabel)}
-
-
-
- {
- setFilterOptions((filterOptionsPrevious) => ({
- ...filterOptionsPrevious,
- includePickedUsers: !filterOptionsPrevious.includePickedUsers,
- }));
- }}
- name="options"
- value="includePickedUsers"
- />
-
- {intl.formatMessage(intlMessages.includePickedUsersLabel)}
-
-
-
-
-
-
- {intl.formatMessage(intlMessages.availableTitle)}
-
-
- {`${users?.length} ${userRoleLabel}: `}
- {makeHorizontalListOfNames(users)}
-
-
-
-
-
- {intl.formatMessage(intlMessages.previouslyPickedTitle)}
-
- {
- deletionFunction([RESET_DATA_CHANNEL]);
- }}
- >
- {intl.formatMessage(intlMessages.clearButtonLabel)}
-
-
-
-
- {
- makeVerticalListOfNames(dataChannelPickedUsers)
- }
-
-
-
- {
- users?.length > 0 ? (
-
+
+
+ {/* FILTER CHIPS */}
+
+
+
+ {intl.formatMessage(intlMessages.filterChipsLabel)}
+
+
+
+ setFilterOptions((prev) => ({
+ ...prev, includeModerators: !prev.includeModerators,
+ }))}
+ />
+
+ {intl.formatMessage(intlMessages.moderatorsChipLabel)}
+
+
+
+ setFilterOptions((prev) => ({
+ ...prev, includePresenter: !prev.includePresenter,
+ }))}
+ />
+
+ {intl.formatMessage(intlMessages.presenterChipLabel)}
+
+
+
+ setFilterOptions((prev) => ({
+ ...prev, includePickedUsers: !prev.includePickedUsers,
+ }))}
+ />
+
+ {intl.formatMessage(intlMessages.pickedUsersChipLabel)}
+
+
+
+
+
+ {/* AVAILABLE USERS SECTION */}
+
+
+
+ {intl.formatMessage(intlMessages.availableTitle)}
+
+
+ {usersCount}
+ {' '}
+ {userRoleLabel}
+
+
+ {usersCount === 0 ? (
+
+
+ {intl.formatMessage(intlMessages.availableEmptyState, { 0: userRoleLabel })}
+
+
+ ) : (
+
+ {users?.map((user) => {
+ const initials = getInitials(user.name);
+ let roleBadgeLabel: string | null = null;
+ if (user.role === 'MODERATOR') {
+ roleBadgeLabel = intl.formatMessage(intlMessages.moderatorRoleLabel);
+ } else if (user.presenter) {
+ roleBadgeLabel = intl.formatMessage(intlMessages.presenterRoleLabel);
+ }
+ return (
+
+ {user.avatar ? (
+
+ ) : (
+
+ {initials}
+
+ )}
+ {user.name}
+ {roleBadgeLabel && (
+ {roleBadgeLabel}
+ )}
+
+ );
+ })}
+
+ )}
+
+
+ {/* PREVIOUSLY PICKED SECTION */}
+
+
+
+ {intl.formatMessage(intlMessages.previouslyPickedTitle)}
+
+ deletionFunction([RESET_DATA_CHANNEL])}
+ >
+ {intl.formatMessage(intlMessages.clearButtonLabel)}
+
+
+ {hasPickedUsers ? (
+
+
+ {makePickedUserRows(dataChannelPickedUsers)}
+
+
+ ) : (
+ <>
+
+
+ {intl.formatMessage(intlMessages.emptyState)}
+
+
+ {/* Empty list kept in DOM so [data-test] li selectors resolve correctly */}
+
+ >
+ )}
+
+
+
+
+ {/* FOOTER */}
+
+ {usersCount > 0 ? (
+ {
- handlePickRandomUser();
- }}
+ onClick={handlePickRandomUser}
>
- {
- (pickedUserWithEntryId)
- ? intl.formatMessage(intlMessages.pickAgainButtonLabel)
- : intl.formatMessage(intlMessages.pickButtonLabel, { 0: userRoleLabel })
- }
-
+ {pickedUserWithEntryId
+ ? intl.formatMessage(includePickedUsers
+ ? intlMessages.pickNextRandomUserButtonLabel
+ : intlMessages.pickAnotherRandomUserButtonLabel)
+ : intl.formatMessage(intlMessages.pickButtonLabel)}
+
) : (
-
+
{intl.formatMessage(intlMessages.noUsersWarning, { 0: userRoleLabel })}
-
- )
- }
-
+
+ )}
+
+
);
}
diff --git a/src/components/modal/presenter-view/styles.tsx b/src/components/modal/presenter-view/styles.tsx
index fb2b8d7..5e8e772 100644
--- a/src/components/modal/presenter-view/styles.tsx
+++ b/src/components/modal/presenter-view/styles.tsx
@@ -1,108 +1,319 @@
import styled from 'styled-components';
-const PresenterViewContentWrapper = styled.div`
- width: '100%';
- height: '100%';
- align-items: 'flex-start';
- display: 'flex';
- flex-direction: 'column';
+// ── Section labels ────────────────────────────────────────────────────────────
+
+const SectionLabel = styled.span`
+ font-size: 0.6875rem;
+ font-weight: 600;
+ color: #8B9AAF;
+ text-transform: uppercase;
+ letter-spacing: 0.6px;
`;
-const PresenterViewSectionWrapper = styled.div`
+// ── Filter chips section ──────────────────────────────────────────────────────
+
+const FilterRow = styled.div`
display: flex;
- align-items: flex-start;
flex-direction: column;
- max-height: 30%;
+ gap: 0.375rem;
`;
-const PresenterViewSectionTitle = styled.div`
- margin: 5px 0px;
+const FilterLabel = styled.span`
+ font-size: 0.8125rem;
font-weight: 600;
- font-size: 20px;
+ color: #8B9AAF;
+ white-space: nowrap;
`;
-const PresenterViewSectionClearAllButton = styled.button`
- padding: 1px 10px;
- margin-left: 8px;
- font-size: 15px;
- background: #efefef;
- border: none;
- color: inherit;
- border-radius: 8px;
+const ChipGroup = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 0.375rem;
+ flex-wrap: wrap;
+`;
+
+const ChipInput = styled.input`
+ display: none;
+`;
+
+const FilterChip = styled.label<{ $active: boolean }>`
+ display: inline-flex;
+ align-items: center;
+ gap: 0.3125rem;
+ padding: 0.25rem 0.625rem;
+ border-radius: 999px;
+ font-size: 0.75rem;
cursor: pointer;
- &:hover {
- background-color: #ddd;
- }
+ user-select: none;
+ transition: all 0.15s;
+
+ ${({ $active }) => ($active ? `
+ background: #EBF1FF;
+ border: 1.5px solid #4E7FF8;
+ color: #4E7FF8;
+ font-weight: 600;
+ ` : `
+ background: #F0F2F6;
+ border: 1.5px solid #D1D9E3;
+ color: #8B9AAF;
+ font-weight: 500;
+ `)}
`;
-const PresenterViewSectionTitleWrapper = styled.div`
+// ── Section header row (label + count/action) ─────────────────────────────────
+
+const SectionHeaderRow = styled.div`
display: flex;
- flex-direction: row;
align-items: center;
+ justify-content: space-between;
+ margin-bottom: 0.5rem;
+`;
+
+// ── Available users section ───────────────────────────────────────────────────
+
+const CountBadge = styled.span`
+ font-size: 0.75rem;
+ color: #4E7FF8;
+ font-weight: 600;
`;
-const PresenterViewSectionListWrapper = styled.div`
+const UserListContainer = styled.div`
+ background: #F7F9FB;
+ border-radius: 0.375rem;
+ padding: 0.625rem 0.75rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.375rem;
+ max-height: 12rem;
overflow-y: auto;
- max-height: 10rem;
- margin-bottom: .75rem;
- width: 100%;
+
+ &::-webkit-scrollbar {
+ width: 4px;
+ }
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 999px;
+ }
+ &::-webkit-scrollbar-button {
+ display: none;
+ }
+ scrollbar-width: thin;
+ scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
`;
-const PresenterViewSectionList = styled.ul`
- font-size: 18px;
- margin: 0;
- list-style-type: none;
+const UserRow = styled.div`
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
`;
-const PresenterViewSectionContent = styled.div`
+const UserAvatar = styled.div<{ $color: string }>`
+ width: 1.625rem;
+ height: 1.625rem;
+ border-radius: 50%;
+ background: ${({ $color }) => $color};
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.625rem;
+ font-weight: 600;
+ color: #fff;
+ flex-shrink: 0;
+`;
+
+const UserAvatarImage = styled.img`
+ width: 1.625rem;
+ height: 1.625rem;
+ border-radius: 50%;
+ object-fit: cover;
+ flex-shrink: 0;
+`;
+
+const UserNameText = styled.span`
+ font-size: 0.8125rem;
+ color: #1C2B3A;
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+`;
+
+const RoleBadge = styled.span`
+ font-size: 0.625rem;
+ color: #8B9AAF;
+ background: #E8EDF2;
+ padding: 0.0625rem 0.375rem;
+ border-radius: 0.1875rem;
+ margin-left: auto;
+ flex-shrink: 0;
+ white-space: nowrap;
+`;
+
+// ── Previously picked section ─────────────────────────────────────────────────
+
+const ClearAllButton = styled.button`
+ font-size: 0.6875rem;
+ color: #8B9AAF;
+ background: none;
+ border: none;
+ text-decoration: underline;
+ text-underline-offset: 2px;
+ cursor: pointer;
+ padding: 0;
+
+ &:hover {
+ color: #6b7d92;
+ }
+`;
+
+const EmptyStateContainer = styled.div`
+ background: #F7F9FB;
+ border-radius: 0.375rem;
+ padding: 0.875rem;
+ text-align: center;
+`;
+
+const EmptyStateText = styled.span`
+ font-size: 0.8125rem;
+ color: #A7B3C3;
+`;
+
+const PickedUserListContainer = styled.div`
+ background: #F7F9FB;
+ border-radius: 0.375rem;
+ padding: 0.625rem 0.75rem;
display: flex;
flex-direction: column;
- font-size: 18px;
- padding-left: 40px;
+ gap: 0.375rem;
+ overflow-y: auto;
+
+ &::-webkit-scrollbar {
+ width: 4px;
+ }
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+ &::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.2);
+ border-radius: 999px;
+ }
+ &::-webkit-scrollbar-button {
+ display: none;
+ }
+ scrollbar-width: thin;
+ scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
`;
-// Section Content related:
+//