Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions packages/shared/src/components/profile/ProfileButton.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ const renderComponent = (user = defaultUser): RenderResult => {
it('should show "Profile settings" tooltip on the profile picture', () => {
renderComponent();

const elementsWithLabel = screen.getAllByLabelText('Profile settings');
// The button itself has aria-label, and the Radix Tooltip trigger also sets aria-label
expect(elementsWithLabel.length).toBeGreaterThanOrEqual(2);
expect(
screen.getByRole('button', { name: 'Profile settings' }),
).toBeInTheDocument();
});

it('should show "Reputation" tooltip on the reputation badge', () => {
Expand Down
63 changes: 32 additions & 31 deletions packages/shared/src/components/profile/ProfileButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import classNames from 'classnames';
import dynamic from 'next/dynamic';
import { useAuthContext } from '../../contexts/AuthContext';
import { ProfilePictureWithIndicator } from './ProfilePictureWithIndicator';
import { CoreIcon, SettingsIcon } from '../icons';
import { CoreIcon, ReputationIcon, SettingsIcon } from '../icons';
import { Button, ButtonSize, ButtonVariant } from '../buttons/Button';
import { useInteractivePopup } from '../../hooks/utils/useInteractivePopup';
import { ReputationUserBadge } from '../ReputationUserBadge';
import { IconSize } from '../Icon';
import { ReadingStreakButton } from '../streak/ReadingStreakButton';
import { useReadingStreak } from '../../hooks/streaks';
import { walletUrl } from '../../lib/constants';
Expand Down Expand Up @@ -50,7 +48,7 @@ export default function ProfileButton({
Partial<Record<QuestRewardType.Reputation | QuestRewardType.Cores, string>>
>({});
const coresCounterRef = useRef<HTMLDivElement | null>(null);
const reputationCounterRef = useRef<HTMLSpanElement | null>(null);
const reputationCounterRef = useRef<HTMLDivElement | null>(null);
const displayedBalance =
typeof animatedCores === 'number'
? animatedCores
Expand Down Expand Up @@ -212,7 +210,6 @@ export default function ProfileButton({
streak={streak}
isLoading={isLoading}
compact
className="pl-4"
/>
)}
{hasCoresAccess && (
Expand All @@ -236,41 +233,45 @@ export default function ProfileButton({
tag="a"
variant={ButtonVariant.Tertiary}
size={ButtonSize.Small}
className="!px-1.5"
>
{largeNumberFormat(displayedBalance)}
</Button>
</Link>
</div>
</Tooltip>
)}
<button
type="button"
aria-label="Profile settings"
className={classNames(
'focus-outline cursor-pointer items-center gap-2 border-none p-0 font-bold text-text-primary no-underline typo-subhead',
className ?? 'flex',
)}
onClick={wrapHandler(() => onUpdate(!isOpen))}
>
<span
<Tooltip content="Reputation">
<div
ref={reputationCounterRef}
className="inline-flex items-center"
data-reward-target={QuestRewardType.Reputation}
className="flex origin-center justify-center will-change-transform"
>
<ReputationUserBadge
className="ml-1 !typo-subhead"
user={{ reputation: displayedReputation ?? 0 }}
iconProps={{
size: IconSize.Small,
}}
/>
</span>
<Tooltip side="bottom" content="Profile settings">
<div className="flex items-center">
<ProfilePictureWithIndicator user={user} />
</div>
</Tooltip>
</button>
<Button
type="button"
data-reward-target={QuestRewardType.Reputation}
icon={<ReputationIcon className="text-accent-onion-default" />}
variant={ButtonVariant.Tertiary}
size={ButtonSize.Small}
className="!pl-0.5 !pr-1.5"
onClick={wrapHandler(() => onUpdate(!isOpen))}
>
{largeNumberFormat(displayedReputation ?? 0)}
</Button>
</div>
</Tooltip>
<Tooltip side="bottom" content="Profile settings">
<button
type="button"
aria-label="Profile settings"
className={classNames(
'focus-outline cursor-pointer items-center border-none bg-transparent p-0',
className ?? 'flex',
)}
onClick={wrapHandler(() => onUpdate(!isOpen))}
>
<ProfilePictureWithIndicator user={user} />
</button>
</Tooltip>
</div>
)}
{isOpen && <ProfileMenu onClose={() => onUpdate(false)} />}
Expand Down
20 changes: 12 additions & 8 deletions packages/shared/src/components/streak/ReadingStreakButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import ConditionalWrapper from '../ConditionalWrapper';
import type { TooltipPosition } from '../tooltips/BaseTooltipContainer';
import { useAuthContext } from '../../contexts/AuthContext';
import { isSameDayInTimezone } from '../../lib/timezones';
import { IconWrapper } from '../Icon';
import { IconSize, IconWrapper } from '../Icon';
import { useStreakTimezoneOk } from '../../hooks/streaks/useStreakTimezoneOk';

interface ReadingStreakButtonProps {
Expand Down Expand Up @@ -122,22 +122,26 @@ export function ReadingStreakButton({
type="button"
iconPosition={iconPosition}
icon={
<IconWrapper wrapperClassName="relative flex items-center gap-2">
<IconWrapper
size={compact ? IconSize.XSmall : undefined}
wrapperClassName={classnames(
'relative flex items-center gap-2',
compact && 'h-6 w-6 justify-center',
)}
>
<ReadingStreakIcon secondary={hasReadToday} />
{!isTimezoneOk && (
<WarningIcon className="!mr-0 text-raw-cheese-40" secondary />
)}
</IconWrapper>
}
variant={
isLaptop || isMobile ? ButtonVariant.Tertiary : ButtonVariant.Float
compact || isLaptop || isMobile
? ButtonVariant.Tertiary
: ButtonVariant.Float
}
onClick={handleToggle}
className={classnames(
'gap-1',
compact && 'text-accent-bacon-default',
className,
)}
className={classnames('gap-1', compact && '!px-1.5', className)}
size={!compact && !isMobile ? ButtonSize.Medium : ButtonSize.Small}
>
{streak?.current}
Expand Down
6 changes: 6 additions & 0 deletions scripts/typecheck-strict-changed.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ const strictSkipList = new Set([
// unrelated to the rightCopy wiring.
'packages/shared/src/contexts/WritePostContext.tsx',
'packages/webapp/pages/squads/create.tsx',
// Header-stat-button alignment branch — touched only to drop the
// bacon-colored number and switch compact to Tertiary. Pre-existing
// strict errors (optional auth user, ConditionalWrapper wrapper type,
// ReactElement vs null return, Button props union) live on unrelated
// lines and should be addressed in a dedicated cleanup PR.
'packages/shared/src/components/streak/ReadingStreakButton.tsx',
]);

const changedFiles = getChangedTypescriptFiles().filter(
Expand Down
Loading