Skip to content

Commit

Permalink
✨ (dashboards) ability to quick-edit widget names from inner report p…
Browse files Browse the repository at this point in the history
…ages (#3587)
  • Loading branch information
MatissJanis authored Oct 7, 2024
1 parent e653ad3 commit 5369494
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 127 deletions.
89 changes: 89 additions & 0 deletions packages/desktop-client/src/components/EditablePageHeaderTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useCallback, useEffect, useState } from 'react';

import { SvgPencil1 } from '../icons/v2';
import { theme } from '../style';

import { Button } from './common/Button2';
import { InitialFocus } from './common/InitialFocus';
import { Input } from './common/Input';
import { View } from './common/View';

type EditablePageHeaderTitleProps = {
title: string;
onSave: (newValue: string) => void;
};

export function EditablePageHeaderTitle({
title: initialTitle,
onSave,
}: EditablePageHeaderTitleProps) {
const [isEditing, setIsEditing] = useState(false);
const [title, setTitle] = useState(initialTitle);

useEffect(() => setTitle(initialTitle), [initialTitle]);

const onSaveValue = useCallback(
(newValue: string) => {
onSave(newValue);
setTitle(newValue);
setIsEditing(false);
},
[onSave],
);

if (isEditing) {
return (
<InitialFocus>
<Input
defaultValue={title}
onEnter={e => onSaveValue(e.currentTarget.value)}
onBlur={e => onSaveValue(e.target.value)}
onEscape={() => setIsEditing(false)}
style={{
fontSize: 25,
fontWeight: 500,
marginTop: -3,
marginBottom: -3,
marginLeft: -6,
paddingTop: 2,
paddingBottom: 2,
width: Math.max(20, title.length) + 'ch',
}}
/>
</InitialFocus>
);
}

return (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
gap: 3,
'& .hover-visible': {
opacity: 0,
transition: 'opacity .25s',
},
'&:hover .hover-visible': {
opacity: 1,
},
}}
>
{title}

<Button
variant="bare"
className="hover-visible"
onPress={() => setIsEditing(true)}
>
<SvgPencil1
style={{
width: 11,
height: 11,
color: theme.pageTextSubdued,
}}
/>
</Button>
</View>
);
}
234 changes: 115 additions & 119 deletions packages/desktop-client/src/components/reports/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { type ComponentProps, type ReactNode } from 'react';
import { useLocation } from 'react-router-dom';

import * as monthUtils from 'loot-core/src/shared/months';
import {
Expand Down Expand Up @@ -61,8 +60,6 @@ export function Header({
children,
}: HeaderProps) {
const isDashboardsFeatureEnabled = useFeatureFlag('dashboards');
const location = useLocation();
const path = location.pathname;
const { isNarrowWidth } = useResponsive();

return (
Expand All @@ -73,141 +70,140 @@ export function Header({
flexShrink: 0,
}}
>
{!['/reports/custom'].includes(path) && (
<View
style={{
flexDirection: isNarrowWidth ? 'column' : 'row',
alignItems: isNarrowWidth ? 'flex-start' : 'center',
marginTop: 15,
gap: 15,
}}
>
{isDashboardsFeatureEnabled && mode && (
<Button
variant={mode === 'static' ? 'normal' : 'primary'}
onPress={() => {
const newMode = mode === 'static' ? 'sliding-window' : 'static';
const [newStart, newEnd] = calculateTimeRange({
start,
end,
mode: newMode,
});

onChangeDates(newStart, newEnd, newMode);
}}
>
{mode === 'static' ? 'Static' : 'Live'}
</Button>
)}

<View
style={{
flexDirection: isNarrowWidth ? 'column' : 'row',
alignItems: isNarrowWidth ? 'flex-start' : 'center',
marginTop: 15,
gap: 15,
flexDirection: 'row',
alignItems: 'center',
gap: 5,
}}
>
{isDashboardsFeatureEnabled && mode && (
<Button
variant={mode === 'static' ? 'normal' : 'primary'}
onPress={() => {
const newMode = mode === 'static' ? 'sliding-window' : 'static';
const [newStart, newEnd] = calculateTimeRange({
start,
<Select
onChange={newValue =>
onChangeDates(
...validateStart(
allMonths[allMonths.length - 1].name,
newValue,
end,
mode: newMode,
});
),
)
}
value={start}
defaultLabel={monthUtils.format(start, 'MMMM, yyyy')}
options={allMonths.map(({ name, pretty }) => [name, pretty])}
/>
<View>to</View>
<Select
onChange={newValue =>
onChangeDates(
...validateEnd(
allMonths[allMonths.length - 1].name,
start,
newValue,
),
)
}
value={end}
options={allMonths.map(({ name, pretty }) => [name, pretty])}
style={{ marginRight: 10 }}
/>
</View>

onChangeDates(newStart, newEnd, newMode);
}}
<View
style={{
flexDirection: 'row',
alignItems: 'center',
gap: 15,
flexWrap: 'wrap',
}}
>
{show1Month && (
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(1))}
>
{mode === 'static' ? 'Static' : 'Live'}
1 month
</Button>
)}

<View
style={{
flexDirection: 'row',
alignItems: 'center',
gap: 5,
}}
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(2))}
>
<Select
onChange={newValue =>
onChangeDates(
...validateStart(
allMonths[allMonths.length - 1].name,
newValue,
end,
),
)
}
value={start}
defaultLabel={monthUtils.format(start, 'MMMM, yyyy')}
options={allMonths.map(({ name, pretty }) => [name, pretty])}
/>
<View>to</View>
<Select
onChange={newValue =>
onChangeDates(
...validateEnd(
allMonths[allMonths.length - 1].name,
start,
newValue,
),
)
}
value={end}
options={allMonths.map(({ name, pretty }) => [name, pretty])}
style={{ marginRight: 10 }}
3 months
</Button>
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(5))}
>
6 months
</Button>
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(11))}
>
1 Year
</Button>
<Button
variant="bare"
onPress={() =>
onChangeDates(
...getFullRange(allMonths[allMonths.length - 1].name),
)
}
>
All Time
</Button>

{filters && (
<FilterButton
compact={isNarrowWidth}
onApply={onApply}
hover={false}
exclude={undefined}
/>
</View>
)}
</View>

{children ? (
<View
style={{
flex: 1,
flexDirection: 'row',
alignItems: 'center',
gap: 15,
flexWrap: 'wrap',
justifyContent: 'flex-end',
}}
>
{show1Month && (
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(1))}
>
1 month
</Button>
)}
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(2))}
>
3 months
</Button>
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(5))}
>
6 months
</Button>
<Button
variant="bare"
onPress={() => onChangeDates(...getLatestRange(11))}
>
1 Year
</Button>
<Button
variant="bare"
onPress={() =>
onChangeDates(
...getFullRange(allMonths[allMonths.length - 1].name),
)
}
>
All Time
</Button>

{filters && (
<FilterButton
compact={isNarrowWidth}
onApply={onApply}
hover={false}
exclude={undefined}
/>
)}
{children}
</View>
) : (
<View style={{ flex: 1 }} />
)}
</View>

{children ? (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
{children}
</View>
) : (
<View style={{ flex: 1 }} />
)}
</View>
)}
{filters && filters.length > 0 && (
<View style={{ marginTop: 5 }}>
<AppliedFilters
Expand Down
Loading

0 comments on commit 5369494

Please sign in to comment.