Skip to content

Commit 6d5c4e6

Browse files
authored
Merge pull request #1558 from session-foundation/fix-pro-badges-qa-issues
fix: qa issues for Pro badges
2 parents 13ee231 + 33588d0 commit 6d5c4e6

28 files changed

+160
-240
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@
9090
"pino": "^9.6.0",
9191
"protobufjs": "^7.4.0",
9292
"punycode": "^2.3.1",
93+
"qrcode.react": "^4.2.0",
9394
"react": "18.3.1",
9495
"react-contexify": "^6.0.0",
9596
"react-dom": "18.3.1",
9697
"react-draggable": "^4.4.6",
9798
"react-error-boundary": "^5.0.0",
9899
"react-h5-audio-player": "^3.9.3",
99100
"react-intersection-observer": "^9.16.0",
100-
"react-qrcode-logo": "^3.0.0",
101101
"react-redux": "8.1.3",
102102
"react-test-renderer": "^18.3.1",
103103
"react-toastify": "^10.0.0",

ts/blueimp-canvas-to-blob.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

ts/components/MemberListItem.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import { assertUnreachable } from '../types/sqlSharedTypes';
3232
import { tr } from '../localization/localeTools';
3333
import { ContactName } from './conversation/ContactName/ContactName';
34+
import type { ContactNameSuffixInMemberList } from './conversation/ContactName/ContactNameContext';
3435

3536
const AvatarContainer = styled.div`
3637
position: relative;
@@ -319,7 +320,11 @@ export const MemberListItem = <T extends string>({
319320
withBorder,
320321
conversationId,
321322
hideRadioButton,
322-
}: MemberListItemProps<T> & { conversationId?: string }) => {
323+
contactNameSuffix,
324+
}: MemberListItemProps<T> & {
325+
conversationId?: string;
326+
contactNameSuffix?: ContactNameSuffixInMemberList;
327+
}) => {
323328
return (
324329
<StyledSessionMemberItem
325330
onClick={() => {
@@ -343,7 +348,7 @@ export const MemberListItem = <T extends string>({
343348
minWidth="0"
344349
>
345350
<ContactName
346-
contactNameContext="member-list-item"
351+
contactNameContext={`member-list-item${contactNameSuffix ?? ''}`}
347352
pubkey={pubkey}
348353
conversationId={conversationId}
349354
/>

ts/components/SessionQRCode.tsx

Lines changed: 49 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
1-
import {
2-
MouseEvent,
3-
useEffect,
4-
useRef,
5-
useState,
6-
type ReactNode,
7-
type SessionDataTestId,
8-
} from 'react';
9-
import { QRCode } from 'react-qrcode-logo';
1+
import { MouseEvent, useEffect, useState, type ReactNode, type SessionDataTestId } from 'react';
2+
import useWindowSize from 'react-use/lib/useWindowSize';
3+
4+
import { QRCodeSVG } from 'qrcode.react';
105
import styled, { CSSProperties } from 'styled-components';
116
import { THEME_GLOBALS } from '../themes/globals';
12-
import { renderQRCode } from '../util/qrCodes';
137
import { AnimatedFlex } from './basic/Flex';
148
import { SessionIconType } from './icon';
15-
import { tr } from '../localization/localeTools';
169

1710
// AnimatedFlex because we fade in the QR code a flicker on first render
1811
const StyledQRView = styled(AnimatedFlex)<{
@@ -24,6 +17,16 @@ const StyledQRView = styled(AnimatedFlex)<{
2417
${props => props.size && `width: ${props.size}px; height: ${props.size}px;`}
2518
`;
2619

20+
const StyledFullScreenQrView = styled(AnimatedFlex)`
21+
top: 0;
22+
left: 0;
23+
width: 100vw;
24+
height: 100vh;
25+
z-index: 3;
26+
background-color: #000000dd;
27+
position: fixed;
28+
`;
29+
2730
export type QRCodeLogoProps = { iconType: SessionIconType; iconSize: number };
2831

2932
export type SessionQRCodeProps = {
@@ -36,7 +39,8 @@ export type SessionQRCodeProps = {
3639
logoImage?: string;
3740
logoSize?: number;
3841
loading?: boolean;
39-
onClick?: (fileName: string, dataUrl: string) => void;
42+
onToggleFullScreen?: () => void;
43+
fullScreen?: boolean;
4044
ariaLabel?: string;
4145
dataTestId?: SessionDataTestId;
4246
style?: CSSProperties;
@@ -52,9 +56,9 @@ export function SessionQRCode(props: SessionQRCodeProps) {
5256
foregroundColor,
5357
hasLogo,
5458
logoImage,
55-
logoSize,
5659
loading,
57-
onClick,
60+
onToggleFullScreen,
61+
fullScreen,
5862
ariaLabel,
5963
dataTestId,
6064
style,
@@ -64,37 +68,13 @@ export function SessionQRCode(props: SessionQRCodeProps) {
6468
const [bgColor, setBgColor] = useState(backgroundColor);
6569
const [fgColor, setFgColor] = useState(foregroundColor);
6670

67-
const qrRef = useRef<QRCode>(null);
6871
const qrCanvasSize = 1000;
69-
const canvasLogoSize = logoSize ? (qrCanvasSize * 0.25 * logoSize) / logoSize : 250;
70-
71-
const loadQRCodeDataUrl = async () => {
72-
const fileName = `${id}-${new Date().toISOString()}.jpg`;
73-
let url = '';
74-
75-
try {
76-
url = await renderQRCode(
77-
{
78-
id: `${id}-save`,
79-
value,
80-
size,
81-
hasLogo,
82-
logoImage,
83-
logoSize,
84-
},
85-
fileName
86-
);
87-
} catch (err) {
88-
window.log.error(`QR code save failed! ${fileName}\n${err}`);
89-
}
90-
return { fileName, url };
91-
};
72+
73+
const { height, width } = useWindowSize();
74+
const smallestDimension = Math.min(height, width);
9275

9376
const handleOnClick = async () => {
94-
const { fileName, url } = await loadQRCodeDataUrl();
95-
if (onClick) {
96-
onClick(fileName, url);
97-
}
77+
onToggleFullScreen?.();
9878
};
9979

10080
useEffect(() => {
@@ -116,14 +96,17 @@ export function SessionQRCode(props: SessionQRCodeProps) {
11696
}
11797
}, [backgroundColor, bgColor, fgColor, foregroundColor, hasLogo, loading, logo, logoImage]);
11898

99+
const Comp = fullScreen ? StyledFullScreenQrView : StyledQRView;
100+
101+
const overriddenSize = fullScreen ? smallestDimension * 0.75 : size;
102+
119103
return (
120-
<StyledQRView
104+
<Comp
121105
$container={true}
122106
$justifyContent="center"
123107
$alignItems="center"
124-
size={size}
108+
size={overriddenSize}
125109
id={id}
126-
title={tr('fullScreenToggle')}
127110
aria-label={ariaLabel || 'QR code'}
128111
onClick={(event: MouseEvent<HTMLDivElement>) => {
129112
event.preventDefault();
@@ -135,25 +118,29 @@ export function SessionQRCode(props: SessionQRCodeProps) {
135118
transition={{ duration: THEME_GLOBALS['--default-duration-seconds'] }}
136119
style={style}
137120
>
138-
<QRCode
139-
ref={qrRef}
140-
id={`${id}-canvas`}
121+
<QRCodeSVG
141122
value={value}
142-
ecLevel={'Q'}
123+
level={'Q'}
143124
size={qrCanvasSize}
144-
bgColor={bgColor}
145-
fgColor={fgColor}
146-
quietZone={40}
147-
logoImage={logo}
148-
logoWidth={canvasLogoSize}
149-
logoHeight={canvasLogoSize}
150-
removeQrCodeBehindLogo={true}
151-
style={{
152-
width: size,
153-
height: size,
154-
}}
125+
bgColor={fullScreen ? 'black' : bgColor}
126+
fgColor={fullScreen ? 'white' : fgColor}
127+
marginSize={2}
128+
style={{ width: overriddenSize, height: overriddenSize }}
129+
imageSettings={
130+
logoImage && !fullScreen
131+
? {
132+
src: logoImage,
133+
x: undefined,
134+
y: undefined,
135+
height: qrCanvasSize * 0.25,
136+
width: qrCanvasSize * 0.25,
137+
opacity: 1,
138+
excavate: true,
139+
}
140+
: undefined
141+
}
155142
/>
156-
{children}
157-
</StyledQRView>
143+
{!fullScreen ? children : null}
144+
</Comp>
158145
);
159146
}

ts/components/SessionWrapperModal.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ const StyledModal = styled.div<{
7777
position: absolute;
7878
top: ${props => (props.$topAnchor === 'center' ? 'auto' : props.$topAnchor)};
7979
max-height: ${props =>
80-
`calc(100vh - ${props.$topAnchor === 'center' ? '' : props.$topAnchor} - 5vh)`};
81-
80+
`calc(100vh - ${props.$topAnchor === 'center' ? '' : `2 * ${props.$topAnchor}`} - 5vh)`}; // 2* to have the modal centered vertically, if it overflows
8281
animation: fadein var(--default-duration);
8382
z-index: 150;
8483
max-width: ${props =>

ts/components/buttons/avatar/UploadFirstImageButton.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,28 @@ import styled from 'styled-components';
22
import { AvatarSize } from '../../avatar/Avatar';
33
import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide';
44
import { LucideIcon } from '../../icon/LucideIcon';
5+
import { useTheme } from '../../../state/theme/selectors/theme';
56
import { PlusAvatarButton } from './PlusAvatarButton';
67

78
const StyledUploadButton = styled.div`
8-
background-color: var(--chat-buttons-background-color);
99
border-radius: 50%;
1010
overflow: hidden;
1111
padding: var(--margins-lg);
1212
aspect-ratio: 1;
1313
`;
1414

1515
export const UploadFirstImageButton = ({ onClick }: { onClick: () => void }) => {
16+
const theme = useTheme();
17+
18+
// we do not have a color that works well for this button on all themes.
19+
const backgroundColor =
20+
theme === 'ocean-dark'
21+
? 'var(--background-primary-color)'
22+
: 'var(--chat-buttons-background-color)';
23+
1624
return (
1725
<div style={{ position: 'relative' }} onClick={onClick}>
18-
<StyledUploadButton>
26+
<StyledUploadButton style={{ backgroundColor }}>
1927
<LucideIcon unicode={LUCIDE_ICONS_UNICODE.IMAGE} iconSize={'max'} />
2028
</StyledUploadButton>
2129
<PlusAvatarButton

ts/components/conversation/ContactName/ContactName.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ function isBoldProfileNameCtx(ctx: ContactNameContext) {
3333
case 'message-author':
3434
case 'message-info-author':
3535
case 'member-list-item':
36+
case 'member-list-item-mention-row':
3637
case 'contact-list-row':
3738
return true;
3839
case 'quote-author':
3940
case 'conversation-list-item-search':
4041
case 'react-list-modal':
41-
case 'message-search-result':
42+
case 'message-search-result-conversation':
43+
case 'message-search-result-from':
4244
return false;
4345
default:
4446
assertUnreachable(ctx, 'isBoldProfileNameCtx');
@@ -49,21 +51,28 @@ function isBoldProfileNameCtx(ctx: ContactNameContext) {
4951
/**
5052
* In some contexts, we want to show the pubkey of the contact.
5153
*/
52-
function isShowPubkeyCtx(ctx: ContactNameContext) {
54+
function isShowPubkeyCtx(ctx: ContactNameContext, isBlinded: boolean) {
5355
// We are doing this as a switch instead of an array so we have to be explicit anytime we add a new context,
5456
// thanks to the assertUnreachable below
5557
switch (ctx) {
5658
case 'message-author':
59+
return true;
5760
case 'message-info-author':
61+
if (isBlinded) {
62+
// we specifically don't want to show the pubkey for blinded senders in message info.
63+
return false;
64+
}
5865
return true;
5966
case 'member-list-item':
67+
case 'member-list-item-mention-row':
6068
case 'contact-list-row':
6169
case 'quote-author':
6270
case 'conversation-list-item':
6371
case 'quoted-message-composition':
6472
case 'conversation-list-item-search':
6573
case 'react-list-modal':
66-
case 'message-search-result':
74+
case 'message-search-result-conversation':
75+
case 'message-search-result-from':
6776
return false;
6877
default:
6978
assertUnreachable(ctx, 'isShowPubkeyCtx');
@@ -82,11 +91,13 @@ function isShowNtsIsYouCtx(ctx: ContactNameContext) {
8291
case 'quote-author':
8392
case 'quoted-message-composition':
8493
case 'react-list-modal':
85-
case 'message-search-result':
8694
case 'member-list-item':
87-
return true;
95+
case 'member-list-item-mention-row':
8896
case 'message-info-author':
97+
case 'message-search-result-from':
98+
return true;
8999
case 'contact-list-row':
100+
case 'message-search-result-conversation':
90101
case 'conversation-list-item':
91102
case 'conversation-list-item-search':
92103
return false;
@@ -105,13 +116,15 @@ function isForceSingleLineCtx(ctx: ContactNameContext) {
105116
switch (ctx) {
106117
case 'message-info-author':
107118
case 'member-list-item':
119+
case 'member-list-item-mention-row':
108120
case 'contact-list-row':
109121
return true;
110122
case 'message-author':
111123
case 'quote-author':
112124
case 'quoted-message-composition':
113125
case 'react-list-modal':
114-
case 'message-search-result':
126+
case 'message-search-result-conversation':
127+
case 'message-search-result-from':
115128
case 'conversation-list-item':
116129
case 'conversation-list-item-search':
117130
return false;
@@ -131,12 +144,14 @@ function isShowUPMOnClickCtx(ctx: ContactNameContext) {
131144
case 'message-info-author':
132145
return true;
133146
case 'member-list-item':
147+
case 'member-list-item-mention-row':
134148
case 'contact-list-row':
135149
case 'message-author':
136150
case 'quote-author':
137151
case 'quoted-message-composition':
138152
case 'react-list-modal':
139-
case 'message-search-result':
153+
case 'message-search-result-conversation':
154+
case 'message-search-result-from':
140155
case 'conversation-list-item':
141156
case 'conversation-list-item-search':
142157
return false;
@@ -183,6 +198,7 @@ export const ContactName = ({
183198
const prefix = module || 'module-contact-name';
184199
const isPublic = useIsPublic(conversationId);
185200
const shortPubkey = PubKey.shorten(pubkey);
201+
const isBlinded = PubKey.isBlinded(pubkey);
186202

187203
const isMe = isUsAnySogsFromCache(pubkey);
188204

@@ -207,7 +223,7 @@ export const ContactName = ({
207223
const shouldShowShortenPkAsName = !displayName;
208224

209225
const shouldShowPubkey =
210-
!shouldShowShortenPkAsName && isPublic && isShowPubkeyCtx(contactNameContext);
226+
!shouldShowShortenPkAsName && isPublic && isShowPubkeyCtx(contactNameContext, isBlinded);
211227
const boldProfileName = isBoldProfileNameCtx(contactNameContext);
212228
const forceSingleLine = isForceSingleLineCtx(contactNameContext);
213229

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
/**
2+
* The MemberListItem component is used in many places, and we sometimes want to hide the pro badge given on the context.
3+
* This suffix will be used to differentiate between the `member-list-item` and a more specific one.
4+
*/
5+
export type ContactNameSuffixInMemberList = '-mention-row' | '';
6+
17
export type ContactNameContext =
28
| 'conversation-list-item'
39
| 'conversation-list-item-search'
@@ -6,6 +12,7 @@ export type ContactNameContext =
612
| 'quote-author' // the author of the quoted message, shown in the message list
713
| 'react-list-modal'
814
| 'message-info-author' // the author of the message as shown in the message info (right panel)
9-
| 'message-search-result'
15+
| 'message-search-result-conversation' // the conversation name in the message search results
16+
| 'message-search-result-from' // the name of the sender in the message search results
1017
| 'contact-list-row' // the name in the list of contacts (after clicking the + from the left pane)
11-
| 'member-list-item';
18+
| `member-list-item${ContactNameSuffixInMemberList}`;

0 commit comments

Comments
 (0)