Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
8f96825
refactor(communicator): add dashboard sections and view-mode constants
RodriSanchez1 Jun 2, 2026
93a4fa9
i18n(communicator): add dashboard messages
RodriSanchez1 Jun 2, 2026
c1f8325
refactor(communicator): extract board logic into hooks
RodriSanchez1 Jun 2, 2026
7d48cd2
feat(communicator): add dashboard presentational components
RodriSanchez1 Jun 2, 2026
6fa8b77
feat(communicator): add shared board dialogs
RodriSanchez1 Jun 2, 2026
ab4b5d5
refactor(communicator): rewrite dialog as a dashboard shell
RodriSanchez1 Jun 2, 2026
c50f85d
refactor(communicator): retarget tour and trim legacy css
RodriSanchez1 Jun 2, 2026
dded18a
chore(communicator): remove obsolete board item and buttons
RodriSanchez1 Jun 2, 2026
fe31e33
test(communicator): cover the dashboard shell
RodriSanchez1 Jun 2, 2026
89060eb
feat: Enhance Communicator Dialog with improved UI components and styles
RodriSanchez1 Jun 2, 2026
bb05c83
feat(communicator): add messages for board management redesign
RodriSanchez1 Aug 7, 2026
439764e
fix(communicator): render toolbar boards in communicator order
RodriSanchez1 Aug 7, 2026
89afa91
feat(communicator): add quick access ordering helpers
RodriSanchez1 Aug 7, 2026
65c6da6
feat(communicator): flatten board action descriptors
RodriSanchez1 Aug 7, 2026
87ef474
feat(communicator): add reorder, export, pdf and show board actions
RodriSanchez1 Aug 7, 2026
6d0ccb6
feat(communicator): add board selection hook
RodriSanchez1 Aug 7, 2026
00d8188
feat(communicator): add polite live region announcer
RodriSanchez1 Aug 7, 2026
cdaa424
perf(communicator): load export helpers lazily to keep pdfmake out of…
RodriSanchez1 Aug 7, 2026
0515228
feat(communicator): add board details presentation
RodriSanchez1 Aug 7, 2026
76ea5e8
feat(communicator): add responsive board details surface
RodriSanchez1 Aug 7, 2026
c2fb3f3
refactor(communicator): make board cards and rows selection triggers
RodriSanchez1 Aug 7, 2026
b0a72f3
refactor(communicator): thread board selection through BoardsView
RodriSanchez1 Aug 7, 2026
52d7847
fix(communicator): match loading skeleton grid to the narrowed board …
RodriSanchez1 Aug 7, 2026
10dbb6c
feat(communicator): add quick access tray
RodriSanchez1 Aug 7, 2026
34088ce
feat(communicator): wire details surface, quick access tray and live …
RodriSanchez1 Aug 7, 2026
9419b91
fix(communicator): point the quick access tour step at the tray
RodriSanchez1 Aug 7, 2026
809fd58
fix(communicator): scope busy clearing to its own board and cancel th…
RodriSanchez1 Aug 7, 2026
60b10b0
refactor(communicator): enhance layout and styling for better respons…
RodriSanchez1 Aug 7, 2026
6ceee0a
refactor(communicator): update snapshot class names for consistency
RodriSanchez1 Aug 7, 2026
76da400
refactor(communicator): add disableAppBarElevation prop to FullScreen…
RodriSanchez1 Aug 7, 2026
8dca0a8
refactor(communicator): update section initialization and icon mappin…
RodriSanchez1 Aug 7, 2026
5da365c
refactor(communicator): implement smooth scrolling on page change in …
RodriSanchez1 Aug 7, 2026
3502f1d
refactor(communicator): update BOARDS_PAGE_LIMIT to improve pagination
RodriSanchez1 Aug 8, 2026
d9a98b8
refactor(communicator): replace ClearIcon and InputIcon with StarIcon…
RodriSanchez1 Aug 8, 2026
8b130c2
refactor(communicator): update pagination logic to display 12 boards …
RodriSanchez1 Aug 8, 2026
2ad7e50
refactor(communicator): update SKELETON_COUNT to use BOARDS_PAGE_LIMI…
RodriSanchez1 Aug 8, 2026
85279f0
refactor(communicator): enhance BoardCard and BoardRow components for…
RodriSanchez1 Aug 8, 2026
453c9ec
refactor(communicator): simplify DashboardNav component and add navig…
RodriSanchez1 Aug 8, 2026
c74f869
refactor(communicator): improve layout and functionality of BoardDeta…
RodriSanchez1 Aug 8, 2026
7f87c93
feat: Implement board management features in CommunicatorDialog
RodriSanchez1 Aug 8, 2026
10d0fbb
refactor(communicator): adjust panel dimensions and padding for impro…
RodriSanchez1 Aug 8, 2026
afa43f0
Merge branch 'master' into refactor/communicatorBuild
RodriSanchez1 Aug 14, 2026
fbaed90
chore: Format files
RodriSanchez1 Aug 14, 2026
73aaca0
Merge remote-tracking branch 'origin/master' into refactor/communicat…
RodriSanchez1 Aug 21, 2026
beac146
refactor: update test descriptions and snapshot for CommunicatorDialog
RodriSanchez1 Aug 21, 2026
8ede039
fix: drop unused pushCommunicator import from CommunicatorDialog cont…
RodriSanchez1 Aug 21, 2026
9802b68
fix: upload local board media before publishing from the communicator…
RodriSanchez1 Aug 21, 2026
0de2dbd
fix: persist communicator membership from board ids so order and remo…
RodriSanchez1 Aug 22, 2026
647ab67
fix: disable the quick access star on the root board in the grid card
RodriSanchez1 Aug 22, 2026
d765a84
fix: disable the quick access star on the root board in the list row
RodriSanchez1 Aug 22, 2026
07786e3
fix: gate set as home board on auth in the quick access tray
RodriSanchez1 Aug 22, 2026
6a2ef5b
fix: cancel the pending search debounce when the dashboard section ch…
RodriSanchez1 Aug 22, 2026
a3de8b0
fix: guard localStorage access for the communicator dialog view mode
RodriSanchez1 Aug 22, 2026
c74a583
fix: key the board details focus effect on the selected board id
RodriSanchez1 Aug 22, 2026
fea0f0f
fix: discard superseded board fetches in the communicator dashboard
RodriSanchez1 Aug 22, 2026
f37dcc6
fix: step back a page when the communicator list empties after a delete
RodriSanchez1 Aug 22, 2026
e2ebdc7
fix: scope the full-height dialog content to the communicator dialog
RodriSanchez1 Aug 22, 2026
3ca8cd0
fix: enhance layout structure in BoardsView and CommunicatorDialog co…
RodriSanchez1 Aug 31, 2026
2ae58af
fix: add hideTitle prop to BoardDetails and update rendering logic in…
RodriSanchez1 Aug 31, 2026
49657f2
chore(i18n): drop dead CommunicatorDialog messages and sync Crowdin s…
RodriSanchez1 Sep 2, 2026
1dd2fc5
feat(ui): add TonalChip, a shared tinted badge
RodriSanchez1 Sep 2, 2026
0b904da
feat(communicator): label board status with chips where there is room
RodriSanchez1 Sep 2, 2026
fe6d589
feat(communicator): add showQuickAccess prop to BoardCard, BoardRow, …
RodriSanchez1 Sep 2, 2026
e7b7620
feat(communicator): add conditional styling for footer and row based …
RodriSanchez1 Sep 2, 2026
200803a
feat(communicator): enhance tour functionality with dynamic steps and…
RodriSanchez1 Sep 2, 2026
097ddc4
fix: keep the home board in quick access and load it into the store
magush27 Oct 5, 2026
dbb8919
fix: cover setting a board outside quick access as home
magush27 Oct 5, 2026
288cd41
fix: keep the home board in quick access and load it into the store
magush27 Oct 5, 2026
2d7dba7
fix: enable the quick access star on a home board missing from quick …
magush27 Oct 5, 2026
0bded3f
fix: enable the quick access star on a home board missing from quick …
magush27 Oct 5, 2026
7e81744
fix: match offline board search as plain text so ( or [ no longer bre…
magush27 Oct 5, 2026
e4d63c0
fix: cover offline board search with regex special characters
magush27 Oct 5, 2026
df44970
fix: move quick access row controls below the title on phones so name…
magush27 Oct 5, 2026
0142d3c
fix: anchor the quick access walkthrough step to the first row so it …
magush27 Oct 5, 2026
5a182cb
fix: mark quick access row controls as the walkthrough target
magush27 Oct 5, 2026
bcdcc5d
fix: cover the quick access walkthrough target
magush27 Oct 5, 2026
e26cf26
refactor(communicator): rework quick access rows with a narrow-screen…
RodriSanchez1 Oct 5, 2026
7f7ea38
Merge remote-tracking branch 'origin/refactor/communicatorBuild' into…
RodriSanchez1 Oct 5, 2026
7381d11
Merge remote-tracking branch 'origin/master' into refactor/communicat…
RodriSanchez1 Oct 5, 2026
7381940
fix(communicator): show the remove icon in the quick access tour legend
RodriSanchez1 Oct 5, 2026
5068c96
fix(communicator): vertically center the quick access row action divider
RodriSanchez1 Oct 5, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import React from 'react';
import PropTypes from 'prop-types';
import { intlShape } from 'react-intl';
import moment from 'moment';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';

import BoardThumb from '../shared/BoardThumb';
import BoardStatusChips from '../shared/BoardStatusChips';
import { formatBoardLocale } from '../utils/boardLocale';
import PremiumFeature from '../../../PremiumFeature';
import messages from '../CommunicatorDialog.messages';

const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1.5),
padding: theme.spacing(1, 2)
},
thumb: {
width: '100%',
height: 120,
borderRadius: theme.shape.borderRadius,
border: `1px solid ${theme.palette.divider}`
},
title: {
fontWeight: 600
},
header: {
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1)
},
meta: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
color: theme.palette.text.secondary
},
separator: {
margin: theme.spacing(0, 0.75),
opacity: 0.5
},
actions: {
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(0.5)
},
action: {
// Full-width, left-aligned, labelled. Comfortably above the 44px target
// minimum in both themes.
justifyContent: 'flex-start',
minHeight: 44,
textTransform: 'none'
},
destructive: {
color: theme.palette.error.main
},
empty: {
padding: theme.spacing(4, 2),
color: theme.palette.text.secondary,
textAlign: 'center'
}
}));

const ActionButton = ({ action, busy, classes }) => {
const button = (
<Button
fullWidth
data-action-key={action.key}
className={`${classes.action} ${
action.destructive ? classes.destructive : ''
}`}
disabled={!!action.disabled || busy}
title={action.hint}
startIcon={action.icon}
onClick={action.onClick}
>
{action.label}
</Button>
);

return action.premium ? <PremiumFeature>{button}</PremiumFeature> : button;
};

ActionButton.propTypes = {
action: PropTypes.object.isRequired,
busy: PropTypes.bool,
classes: PropTypes.object.isRequired
};

const BoardDetails = ({
intl,
board,
actions,
busy,
communicator,
activeBoardId,
headingRef,
hideTitle
}) => {
const classes = useStyles();

if (!board) {
return (
<div className={classes.empty}>
<Typography variant="body2">
{intl.formatMessage(messages.selectBoardPrompt)}
</Typography>
</div>
);
}

const title = board.name || board.id;
const locale = formatBoardLocale(intl, board.locale);
const metaParts = [
intl.formatMessage(messages.tilesQty, { qty: board.tiles.length }),
locale,
moment(board.lastEdited).format('DD/MM/YYYY')
].filter(Boolean);

return (
<div className={classes.root}>
<BoardThumb board={board} className={classes.thumb} />

<div className={classes.header}>
{!hideTitle && (
<Typography
variant="h6"
component="h2"
className={classes.title}
tabIndex={-1}
ref={headingRef}
>
{title}
</Typography>
)}
<Typography variant="caption" component="p" className={classes.meta}>
{metaParts.map((part, index) => (
<React.Fragment key={part}>
{index > 0 && (
<span className={classes.separator} aria-hidden="true">
·
</span>
)}
{part}
</React.Fragment>
))}
</Typography>
{communicator && (
<BoardStatusChips
intl={intl}
board={board}
isRoot={communicator.rootBoard === board.id}
isActive={activeBoardId === board.id}
/>
)}
</div>

<Divider />

<div className={classes.actions}>
{actions.map((action) => (
<ActionButton
key={action.key}
action={action}
busy={busy}
classes={classes}
/>
))}
</div>
</div>
);
};

BoardDetails.defaultProps = {
actions: [],
busy: false,
hideTitle: false
};

BoardDetails.propTypes = {
intl: intlShape.isRequired,
board: PropTypes.object,
actions: PropTypes.array,
busy: PropTypes.bool,
communicator: PropTypes.object,
activeBoardId: PropTypes.string,
headingRef: PropTypes.object,
hideTitle: PropTypes.bool
};

export default BoardDetails;
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React from 'react';
import { mount } from 'enzyme';
import Button from '@material-ui/core/Button';
import BoardDetails from './BoardDetails';

jest.mock('../CommunicatorDialog.messages', () => ({
__esModule: true,
default: new Proxy(
{},
{
get: (target, prop) => ({
id: String(prop),
defaultMessage: String(prop)
})
}
)
}));

jest.mock('../shared/BoardThumb', () => ({
__esModule: true,
default: () => null
}));

const intl = { formatMessage: ({ defaultMessage }) => defaultMessage };

const board = {
id: 'b1',
name: 'Comidas',
tiles: [{ id: 't1' }, { id: 't2' }],
lastEdited: '2026-01-01T00:00:00.000Z'
};

const actions = [
{ key: 'show', label: 'Show', icon: null, onClick: jest.fn() },
{
key: 'clone',
label: 'Clone',
icon: null,
disabled: true,
onClick: jest.fn()
},
{
key: 'delete',
label: 'Delete',
icon: null,
destructive: true,
onClick: jest.fn()
}
];

const render = (props = {}) =>
mount(
<BoardDetails
intl={intl}
board={board}
actions={actions}
busy={false}
onClose={jest.fn()}
{...props}
/>
);

describe('BoardDetails', () => {
it('renders the board name', () => {
expect(render().text()).toContain('Comidas');
});

it('renders one button per action with a visible label', () => {
const buttons = render()
.find(Button)
.filterWhere((node) => !!node.prop('data-action-key'));
expect(buttons).toHaveLength(3);
expect(buttons.map((node) => node.text())).toEqual(
expect.arrayContaining(['Show', 'Clone', 'Delete'])
);
});

it('disables an action marked disabled', () => {
const clone = render()
.find(Button)
.filterWhere((node) => node.prop('data-action-key') === 'clone');
expect(clone.prop('disabled')).toBe(true);
});

it('disables every action while busy', () => {
const show = render({ busy: true })
.find(Button)
.filterWhere((node) => node.prop('data-action-key') === 'show');
expect(show.prop('disabled')).toBe(true);
});

it('calls the action handler on click', () => {
const onClick = jest.fn();
const wrapper = render({
actions: [{ key: 'show', label: 'Show', icon: null, onClick }]
});

wrapper
.find(Button)
.filterWhere((node) => node.prop('data-action-key') === 'show')
.simulate('click');

expect(onClick).toHaveBeenCalled();
});

it('renders a prompt when nothing is selected', () => {
expect(render({ board: null }).text()).toContain('selectBoardPrompt');
});
});
Loading
Loading