diff --git a/functions/src/definitions/common/parameters/userResponses.json b/functions/src/definitions/common/parameters/userResponses.json index a4f11f4..eace389 100644 --- a/functions/src/definitions/common/parameters/userResponses.json +++ b/functions/src/definitions/common/parameters/userResponses.json @@ -284,6 +284,10 @@ "cn": "您的免费额度将在午夜重置。如果您觉得我们的服务有用,可以通过以下链接加入我们的高级订阅候补名单——每月仅需一杯咖啡的价格($4.99),即可享受您或您所关心的人{{paid_tier_limit}}次提交,并帮助我们维持服务运营!" }, "OUT_OF_SUBMISSIONS": { + "en": "Thank you for your active engagement with CheckMate. Unfortunately, you've reached our daily limit. This will reset at midnight.\n\nWe appreciate your understanding and continued support as we work to serve everyone as efficiently as possible.", + "cn": "感谢您积极使用查友。很遗憾,您已达到今日使用限额。限额将在午夜重置。\n在我们努力为所有用户提供高效服务的同时,感谢您的理解与持续支持。" + }, + "OUT_OF_SUBMISSIONS_THANKS": { "en": "Thanks for using CheckMate 🙏🏻.\n\n You have run out of your {{free_tier_limit}} free daily submissions. We thank you for your interest in our paid subscriber tier and appreciate your patience as we work to implement it.", "cn": "感谢使用 查友 🙏🏻。\n\n您今日 {{free_tier_limit}} 次的免费提交机会已用完。我们感谢您对高级会员服务的关注,并感谢您的耐心等待,我们正在努力推出该服务。" }, @@ -515,4 +519,4 @@ "en": "Get more!", "cn": "获取更多!" } -} +} \ No newline at end of file diff --git a/functions/src/definitions/common/responseUtils.ts b/functions/src/definitions/common/responseUtils.ts index 5daf5aa..712af6d 100644 --- a/functions/src/definitions/common/responseUtils.ts +++ b/functions/src/definitions/common/responseUtils.ts @@ -297,20 +297,16 @@ async function sendMenuMessage( functions.logger.error(`prefixName ${prefixName} not found in responses`) return } - let text = getFinalResponseText( - responses.MENU, + const isTester = userSnap.get("isTester") ?? false + let text = getFinalResponseText({ + responseText: responses.MENU, responses, - null, - null, - false, - false, - false, - false, isGenerated, isIncorrect, - "irrelevant", - prefixName - ) + primaryCategory: "irrelevant", + prefixName, + isTester, + }) switch (platform) { case "telegram": @@ -909,6 +905,7 @@ async function respondToInstance( ) } const language = userSnap.get("language") ?? "en" + const isTester = userSnap.get("isTester") ?? false const responses = await getResponsesObj("user", language) const numSubmissionsRemaining = userSnap.get("numSubmissionsRemaining") const monthlySubmissionLimit = userSnap.get("monthlySubmissionLimit") @@ -1016,7 +1013,7 @@ async function respondToInstance( let communityNoteMessageId = null - if (communityNote && !communityNote.downvoted) { + if (communityNote && !communityNote.downvoted && isTester) { category = "communityNote" bespokeReply = true //get the text based on language @@ -1109,12 +1106,14 @@ async function respondToInstance( let responseText switch (category) { case "irrelevant_auto": - responseText = getFinalResponseText( - responses["IRRELEVANT_AUTO"], + responseText = getFinalResponseText({ + responseText: responses["IRRELEVANT_AUTO"], responses, - numSubmissionsRemaining, - monthlySubmissionLimit - ) + remainingSubmissions: numSubmissionsRemaining, + freeTierLimit: monthlySubmissionLimit, + primaryCategory: "irrelevant", + isTester, + }) const misunderstoodButton = { type: "reply", reply: { @@ -1144,7 +1143,12 @@ async function respondToInstance( ) break case "error": - responseText = getFinalResponseText(responses.ERROR, responses) + responseText = getFinalResponseText({ + responseText: responses.ERROR, + responses, + primaryCategory: "error", + isTester, + }) await sendTextMessage("user", from, responseText, replyId) break case "custom": @@ -1168,21 +1172,21 @@ async function respondToInstance( parentMessageRef, language ) - const responseText = getFinalResponseText( - responses["UNSURE"], + const responseText = getFinalResponseText({ + responseText: responses["UNSURE"], responses, - numSubmissionsRemaining, - monthlySubmissionLimit, + remainingSubmissions: numSubmissionsRemaining, + freeTierLimit: monthlySubmissionLimit, isMachineCategorised, isMatched, isImage, hasCaption, isGenerated, isIncorrect, - "unsure", - null, - votingStatsResponse - ) + primaryCategory: "unsure", + votingStats: votingStatsResponse, + isTester, + }) //reinstate count if we really unsure. await userSnap.ref.update({ numSubmissionsRemaining: FieldValue.increment(1), @@ -1195,21 +1199,20 @@ async function respondToInstance( functions.logger.error(`category ${category} not found in responses`) return } - responseText = getFinalResponseText( - responses[category.toUpperCase() as keyof typeof responses], + responseText = getFinalResponseText({ + responseText: responses[category.toUpperCase()], responses, - numSubmissionsRemaining, - monthlySubmissionLimit, + remainingSubmissions: numSubmissionsRemaining, + freeTierLimit: monthlySubmissionLimit, isMachineCategorised, isMatched, isImage, hasCaption, isGenerated, isIncorrect, - category, - null, - null - ) + primaryCategory: category, + isTester, + }) if (!(isMachineCategorised || validResponsesCount <= 0)) { buttons.push(votingResultsButton) @@ -1220,7 +1223,9 @@ async function respondToInstance( updateObj.scamShieldConsent = true } - buttons.push(getMoreChecksButton) + if (isTester) { + buttons.push(getMoreChecksButton) + } if (buttons.length > 0) { await sendWhatsappButtonMessage( @@ -1269,6 +1274,10 @@ async function sendWaitingMessage( userSnap: DocumentSnapshot, replyMessageId: string | null = null ) { + const isTester = userSnap.get("isTester") ?? false + if (!isTester) { + return + } const language = userSnap.get("language") ?? "en" const responses = await getResponsesObj("user", language) await sendTextMessage( @@ -1474,7 +1483,6 @@ async function sendGetMoreSubmissionsMessage( const responses = await getResponsesObj("user", language) const hasExpressedInterest = userSnap.get("isInterestedInSubscription") const isPaidTier = userSnap.get("tier") !== "free" - //TODO: change to whatsapp flow if (isPaidTier || hasExpressedInterest) { const responseText = responses.GET_MORE_SUBMISSIONS await sendTextMessage( @@ -1524,8 +1532,21 @@ async function sendOutOfSubmissionsMessage(userSnap: DocumentSnapshot) { const hasExpressedInterest = userSnap.get("isInterestedInSubscription") const isPaidTier = userSnap.get("tier") !== "free" const paidTierLimit = thresholds.paidTierDailyLimit ?? 50 + const isTester = userSnap.get("isTester") ?? false + if (!isTester) { + const responseText = responses.OUT_OF_SUBMISSIONS + await sendTextMessage( + "user", + whatsappId, + responseText, + null, + "whatsapp", + true + ) + return + } if (isPaidTier || hasExpressedInterest) { - const responseText = responses.OUT_OF_SUBMISSIONS.replace( + const responseText = responses.OUT_OF_SUBMISSIONS_THANKS.replace( "{{free_tier_limit}}", monthlySubmissionLimit.toString() ) @@ -1798,21 +1819,39 @@ async function sendBlast(userSnap: DocumentSnapshot) { ) } -function getFinalResponseText( - responseText: string, - responses: ResponseObject, - remainingSubmissions: number | null = null, - freeTierLimit: number | null = null, - isMachineCategorised: boolean = false, - isMatched: boolean = false, - isImage: boolean = false, - hasCaption: boolean = false, - isGenerated: boolean = false, - isIncorrect: boolean = false, - primaryCategory: string = "irrelevant", - prefixName: string | null = null, - votingStats: string | null = null -) { +interface GetFinalResponseParams { + responseText: string + responses: Record + remainingSubmissions?: number + freeTierLimit?: number + isMachineCategorised?: boolean + isMatched?: boolean + isImage?: boolean + hasCaption?: boolean + isGenerated?: boolean + isIncorrect?: boolean + primaryCategory?: string + prefixName?: string + votingStats?: string + isTester?: boolean +} + +function getFinalResponseText({ + responseText, + responses, + remainingSubmissions = undefined, + freeTierLimit = undefined, + isMachineCategorised = false, + isMatched = false, + isImage = false, + hasCaption = false, + isGenerated = false, + isIncorrect = false, + primaryCategory = "irrelevant", + prefixName = "", + votingStats = "", + isTester = false, +}: GetFinalResponseParams): string { let finalResponse = responseText .replace("{{prefix}}", prefixName ? responses[prefixName] : "") .replace( @@ -1836,16 +1875,17 @@ function getFinalResponseText( ? responses.INCORRECT_TRIVIAL : "" ) - .replace("{{voting_stats}}", votingStats ?? "") + .replace("{{voting_stats}}", votingStats) .replace( "{{submissions_remaining}}", - responses.REMAINING_SUBMISSIONS_SUFFIX + isTester ? responses.REMAINING_SUBMISSIONS_SUFFIX : "" ) .replace( "{{num_remaining_submissions}}", - remainingSubmissions?.toString() ?? "" + remainingSubmissions?.toString() || "" ) - .replace("{{free_tier_limit}}", freeTierLimit?.toString() ?? "") + .replace("{{free_tier_limit}}", freeTierLimit?.toString() || "") + return finalResponse } diff --git a/functions/src/services/user/userManagement.ts b/functions/src/services/user/userManagement.ts index 216de67..24f5e32 100644 --- a/functions/src/services/user/userManagement.ts +++ b/functions/src/services/user/userManagement.ts @@ -5,6 +5,7 @@ import { UserData } from "../../types" import { logger } from "firebase-functions/v2" import { getThresholds } from "../../definitions/common/utils" const salt = process.env.HASHIDS_SALT +const environment = process.env.ENVIRONMENT const hashids = new Hashids(salt) if (!admin.apps.length) { admin.initializeApp() @@ -91,6 +92,10 @@ export async function createNewUser( tier: "free", numSubmissionsRemaining: thresholds.freeTierDailyLimit ?? 5, monthlySubmissionLimit: thresholds.freeTierDailyLimit ?? 5, + isTester: + environment === "UAT" || environment === "DEV" || environment === "SIT" + ? true + : false, } try { const res = await db.collection("users").add(newUserObject) diff --git a/functions/src/types.ts b/functions/src/types.ts index a5e1829..f816230 100644 --- a/functions/src/types.ts +++ b/functions/src/types.ts @@ -258,6 +258,7 @@ export type UserData = { priceWhereInterested: number | null // The price point when the user is interested feedback: string | null // The user's feedback, if they've provided any tier: "free" | "paid" + isTester: boolean } export type CheckerData = {