Gift Badges: A few tweaks

This commit is contained in:
Scott Nonnenberg 2022-05-16 12:54:38 -07:00 committed by GitHub
parent 0a0b5a7bfe
commit a114e4e210
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 134 additions and 124 deletions

View file

@ -1268,11 +1268,6 @@ $message-padding-horizontal: 12px;
} }
} }
.module-message__unopened-gift-badge__container {
cursor: pointer;
user-select: none;
}
.module-message__unopened-gift-badge { .module-message__unopened-gift-badge {
width: 240px; width: 240px;
height: 132px; height: 132px;
@ -1285,9 +1280,8 @@ $message-padding-horizontal: 12px;
top: -$message-padding-vertical; top: -$message-padding-vertical;
bottom: $message-padding-vertical; bottom: $message-padding-vertical;
} }
}
.module-message__unopened-gift-badge--outgoing { &--outgoing {
@include light-theme { @include light-theme {
border-bottom: 1px solid $color-white-alpha-80; border-bottom: 1px solid $color-white-alpha-80;
} }
@ -1296,7 +1290,12 @@ $message-padding-horizontal: 12px;
} }
} }
.module-message__unopened-gift-badge__ribbon-horizontal { &__container {
cursor: default;
user-select: none;
}
&__ribbon-horizontal {
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
@ -1305,7 +1304,8 @@ $message-padding-horizontal: 12px;
transform: translateY(-50%); transform: translateY(-50%);
background-color: $color-white; background-color: $color-white;
} }
.module-message__unopened-gift-badge__ribbon-vertical {
&__ribbon-vertical {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
@ -1314,7 +1314,8 @@ $message-padding-horizontal: 12px;
transform: translateX(-50%); transform: translateX(-50%);
background-color: $color-white; background-color: $color-white;
} }
.module-message__unopened-gift-badge__bow {
&__bow {
position: absolute; position: absolute;
// Centered // Centered
@ -1330,10 +1331,10 @@ $message-padding-horizontal: 12px;
height: 60px; height: 60px;
} }
.module-message__unopened-gift-badge__text { &__text {
@include font-body-2; @include font-body-2-italic;
}
.module-message__unopened-gift-badge__text--incoming { &--incoming {
@include light-theme { @include light-theme {
color: $color-gray-60; color: $color-gray-60;
} }
@ -1341,9 +1342,10 @@ $message-padding-horizontal: 12px;
color: $color-gray-25; color: $color-gray-25;
} }
} }
.module-message__unopened-gift-badge__container }
.module-message__text--incoming {
@include font-body-2; &__container .module-message__text--incoming {
@include font-body-2-italic;
@include light-theme { @include light-theme {
color: $color-gray-60; color: $color-gray-60;
@ -1352,9 +1354,8 @@ $message-padding-horizontal: 12px;
color: $color-gray-25; color: $color-gray-25;
} }
} }
.module-message__unopened-gift-badge__container &__container .module-message__text--outgoing {
.module-message__text--outgoing { @include font-body-2-italic;
@include font-body-2;
@include light-theme { @include light-theme {
color: $color-white-alpha-80; color: $color-white-alpha-80;
@ -1363,6 +1364,7 @@ $message-padding-horizontal: 12px;
color: $color-white-alpha-80; color: $color-white-alpha-80;
} }
} }
}
.module-message__redeemed-gift-badge { .module-message__redeemed-gift-badge {
display: flex; display: flex;

View file

@ -62,7 +62,7 @@ export function parseBoostBadgeListFromServer(
const parsed = parseBadgeFromServer(item.badge, updatesUrl); const parsed = parseBadgeFromServer(item.badge, updatesUrl);
if (parsed) { if (parsed) {
result[`BOOST-${level}`] = parsed; result[level] = parsed;
} }
}); });

View file

@ -1727,9 +1727,10 @@ story.add('EmbeddedContact: Loading Avatar', () => {
story.add('Gift Badge: Unopened', () => { story.add('Gift Badge: Unopened', () => {
const props = createProps({ const props = createProps({
giftBadge: { giftBadge: {
state: GiftBadgeStates.Unopened, id: 'GIFT',
expiration: Date.now() + DAY * 30, expiration: Date.now() + DAY * 30,
level: 3, level: 3,
state: GiftBadgeStates.Unopened,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
@ -1738,7 +1739,7 @@ story.add('Gift Badge: Unopened', () => {
const getPreferredBadge = () => ({ const getPreferredBadge = () => ({
category: BadgeCategory.Donor, category: BadgeCategory.Donor,
descriptionTemplate: 'This is a description of the badge', descriptionTemplate: 'This is a description of the badge',
id: 'BOOST-3', id: 'GIFT',
images: [ images: [
{ {
transparent: { transparent: {
@ -1754,9 +1755,10 @@ story.add('Gift Badge: Redeemed (30 days)', () => {
const props = createProps({ const props = createProps({
getPreferredBadge, getPreferredBadge,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now() + DAY * 30 + SECOND, expiration: Date.now() + DAY * 30 + SECOND,
id: 'GIFT',
level: 3, level: 3,
state: GiftBadgeStates.Redeemed,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
@ -1766,21 +1768,23 @@ story.add('Gift Badge: Redeemed (24 hours)', () => {
const props = createProps({ const props = createProps({
getPreferredBadge, getPreferredBadge,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now() + DAY + SECOND, expiration: Date.now() + DAY + SECOND,
id: 'GIFT',
level: 3, level: 3,
state: GiftBadgeStates.Redeemed,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
}); });
story.add('Gift Badge: Redeemed (60 minutes)', () => { story.add('Gift Badge: Opened (60 minutes)', () => {
const props = createProps({ const props = createProps({
getPreferredBadge, getPreferredBadge,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now() + HOUR + SECOND, expiration: Date.now() + HOUR + SECOND,
id: 'GIFT',
level: 3, level: 3,
state: GiftBadgeStates.Opened,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
@ -1790,21 +1794,23 @@ story.add('Gift Badge: Redeemed (1 minute)', () => {
const props = createProps({ const props = createProps({
getPreferredBadge, getPreferredBadge,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now() + MINUTE + SECOND, expiration: Date.now() + MINUTE + SECOND,
id: 'GIFT',
level: 3, level: 3,
state: GiftBadgeStates.Redeemed,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
}); });
story.add('Gift Badge: Redeemed (expired)', () => { story.add('Gift Badge: Opened (expired)', () => {
const props = createProps({ const props = createProps({
getPreferredBadge, getPreferredBadge,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now(), expiration: Date.now(),
id: 'GIFT',
level: 3, level: 3,
state: GiftBadgeStates.Opened,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);
@ -1814,9 +1820,10 @@ story.add('Gift Badge: Missing Badge', () => {
const props = createProps({ const props = createProps({
getPreferredBadge: () => undefined, getPreferredBadge: () => undefined,
giftBadge: { giftBadge: {
state: GiftBadgeStates.Redeemed,
expiration: Date.now() + MINUTE + SECOND, expiration: Date.now() + MINUTE + SECOND,
id: 'MISSING',
level: 3, level: 3,
state: GiftBadgeStates.Redeemed,
}, },
}); });
return renderBothDirections(props); return renderBothDirections(props);

View file

@ -180,12 +180,14 @@ export type AudioAttachmentProps = {
export enum GiftBadgeStates { export enum GiftBadgeStates {
Unopened = 'Unopened', Unopened = 'Unopened',
Opened = 'Opened',
Redeemed = 'Redeemed', Redeemed = 'Redeemed',
} }
export type GiftBadgeType = { export type GiftBadgeType = {
level: number;
expiration: number; expiration: number;
state: GiftBadgeStates.Redeemed | GiftBadgeStates.Unopened; id: string | undefined;
level: number;
state: GiftBadgeStates;
}; };
export type PropsData = { export type PropsData = {
@ -1329,8 +1331,11 @@ export class Message extends React.PureComponent<Props, State> {
); );
} }
if (giftBadge.state === GiftBadgeStates.Redeemed) { if (
const badgeId = `BOOST-${giftBadge.level}`; giftBadge.state === GiftBadgeStates.Redeemed ||
giftBadge.state === GiftBadgeStates.Opened
) {
const badgeId = giftBadge.id || `BOOST-${giftBadge.level}`;
const badgeSize = 64; const badgeSize = 64;
const badge = getPreferredBadge([{ id: badgeId }]); const badge = getPreferredBadge([{ id: badgeId }]);
const badgeImagePath = getBadgeImageFileLocalPath( const badgeImagePath = getBadgeImageFileLocalPath(

View file

@ -348,7 +348,7 @@ story.add('Video Tap-to-View', () => {
story.add('Gift Badge', () => { story.add('Gift Badge', () => {
const props = createProps({ const props = createProps({
text: '', text: "Some text which shouldn't be rendered",
isGiftBadge: true, isGiftBadge: true,
}); });

View file

@ -333,7 +333,7 @@ export class Quote extends React.Component<Props, State> {
isViewOnce, isViewOnce,
} = this.props; } = this.props;
if (text) { if (text && !isGiftBadge) {
const quoteText = bodyRanges const quoteText = bodyRanges
? getTextWithMentions(bodyRanges, text) ? getTextWithMentions(bodyRanges, text)
: text; : text;

View file

@ -98,7 +98,9 @@ export class ViewSyncs extends Collection {
message.set({ message.set({
giftBadge: { giftBadge: {
...giftBadge, ...giftBadge,
state: GiftBadgeStates.Redeemed, state: isIncoming(message.attributes)
? GiftBadgeStates.Redeemed
: GiftBadgeStates.Opened,
}, },
}); });
} }

1
ts/model-types.d.ts vendored
View file

@ -183,6 +183,7 @@ export type MessageAttributesType = {
giftBadge?: { giftBadge?: {
expiration: number; expiration: number;
level: number; level: number;
id: string | undefined;
receiptCredentialPresentation: string; receiptCredentialPresentation: string;
state: GiftBadgeStates; state: GiftBadgeStates;
}; };

View file

@ -2682,10 +2682,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const giftBadge = message.get('giftBadge'); const giftBadge = message.get('giftBadge');
if (giftBadge) { if (giftBadge) {
const { level } = giftBadge; const { level } = giftBadge;
const existingBadgesById = reduxState.badges.byId;
const badgeId = `BOOST-${level}`;
if (!existingBadgesById[badgeId]) {
const { updatesUrl } = window.SignalContext.config; const { updatesUrl } = window.SignalContext.config;
strictAssert( strictAssert(
typeof updatesUrl === 'string', typeof updatesUrl === 'string',
@ -2699,23 +2695,18 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await window.textsecure.messaging.server.getBoostBadgesFromServer( await window.textsecure.messaging.server.getBoostBadgesFromServer(
userLanguages userLanguages
); );
const boostBadges = parseBoostBadgeListFromServer( const boostBadgesByLevel = parseBoostBadgeListFromServer(
response, response,
updatesUrl updatesUrl
); );
const badge = boostBadges[badgeId]; const badge = boostBadgesByLevel[level];
if (!badge) { if (!badge) {
log.error( log.error(
`handleDataMessage: gift badge ${badgeId} not found on server` `handleDataMessage: gift badge with level ${level} not found on server`
); );
} else { } else {
await window.reduxActions.badges.updateOrCreate([ await window.reduxActions.badges.updateOrCreate([badge]);
{ giftBadge.id = badge.id;
...badge,
id: badgeId,
},
]);
}
} }
} }

View file

@ -189,9 +189,10 @@ export type ProcessedGroupCallUpdate = Proto.DataMessage.IGroupCallUpdate;
export type ProcessedStoryContext = Proto.DataMessage.IStoryContext; export type ProcessedStoryContext = Proto.DataMessage.IStoryContext;
export type ProcessedGiftBadge = { export type ProcessedGiftBadge = {
receiptCredentialPresentation: string;
level: number;
expiration: number; expiration: number;
id: string | undefined;
level: number;
receiptCredentialPresentation: string;
state: GiftBadgeStates; state: GiftBadgeStates;
}; };

View file

@ -249,6 +249,7 @@ export function processGiftBadge(
return { return {
expiration: timestamp + Number(receipt.getReceiptExpirationTime()), expiration: timestamp + Number(receipt.getReceiptExpirationTime()),
id: undefined,
level: Number(receipt.getReceiptLevel()), level: Number(receipt.getReceiptLevel()),
receiptCredentialPresentation: Bytes.toBase64( receiptCredentialPresentation: Bytes.toBase64(
giftBadge.receiptCredentialPresentation giftBadge.receiptCredentialPresentation