From 0ac15920a477a5c8090fd2b929b36ac0b6e02c34 Mon Sep 17 00:00:00 2001
From: Eric Bailey <git@esb.lol>
Date: Fri, 18 Apr 2025 21:15:32 -0500
Subject: Verification (#8226)

* WIP

* Alignment with icon

* Add create/remove prompts

* Fill out check dialog a bit

* Reorg

* Handle was verified state

* Add warning to edit profile

* Add warning to handle dialog

* Decent alignment in posts on all platforms

* Refactor alignment for posts, chatlist, hover card

* Disable on profile

* Convo header

* Compute simple verification state

* Add other icon, rename, integrate

* Swap in simple state for profile edits

* Clean up utility hooks

* Add verifications UI to dialog

* Add edu nux

* Revert change

* Fix wrapping of check on profile

* Rename

* Fix gap under PostMeta

* Update check dialogs

* Handle takendown verifiers in check dialog

* alf composer reply to

* Refactor verification state

* Add create/remove mutations, non-functional for now

* Fix up post-rebase

* Add check to first author noty

* Do cache updates after mutations

* DRY up hook, add to profile updates too

* Add to drawer

* Update account list

* Adapt to new types

* Hook up mutations

* Use profile shadow in feeds

* Add to settings

* Shadow currentAccountProfile

* Add invalid state to verifications

* Fix alignment and overflow in Settings and Drawer

* Re-integrate post rebase

* Remove debug code

* Update copy

* Add unverified notification support

* Remove link

* Make sure dialog closes

* Update URL

* Add settings screen

* Integrate new setting into verification states

* Add metrics, bump package, fix bad import

* NUX fixes

* Update copy

* Fixes

* Update types

* fix search autocomplete

* fix lint

* add display name warning to new dialog

* update default prefs

* Add parsing support for notifications

* Bump pkg

* Tweak noty styles

* Adjust check alignment

* Tweak check alignment

* Fix badge for verifier

* Modify copy

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
---
 .../verification/VerificationCheckButton.tsx       | 155 +++++++++++++++++++++
 1 file changed, 155 insertions(+)
 create mode 100644 src/components/verification/VerificationCheckButton.tsx

(limited to 'src/components/verification/VerificationCheckButton.tsx')

diff --git a/src/components/verification/VerificationCheckButton.tsx b/src/components/verification/VerificationCheckButton.tsx
new file mode 100644
index 000000000..1b66cd90e
--- /dev/null
+++ b/src/components/verification/VerificationCheckButton.tsx
@@ -0,0 +1,155 @@
+import {View} from 'react-native'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {logger} from '#/logger'
+import {type Shadow} from '#/state/cache/types'
+import {atoms as a, useBreakpoints, useTheme} from '#/alf'
+import {Button} from '#/components/Button'
+import {useDialogControl} from '#/components/Dialog'
+import {useFullVerificationState} from '#/components/verification'
+import {type FullVerificationState} from '#/components/verification'
+import {VerificationCheck} from '#/components/verification/VerificationCheck'
+import {VerificationsDialog} from '#/components/verification/VerificationsDialog'
+import {VerifierDialog} from '#/components/verification/VerifierDialog'
+import type * as bsky from '#/types/bsky'
+
+export function shouldShowVerificationCheckButton(
+  state: FullVerificationState,
+) {
+  let ok = false
+
+  if (state.profile.role === 'default') {
+    if (state.profile.isVerified) {
+      ok = true
+    } else if (state.profile.isViewer && state.profile.wasVerified) {
+      ok = true
+    } else if (
+      state.viewer.role === 'verifier' &&
+      state.viewer.hasIssuedVerification
+    ) {
+      ok = true
+    }
+  } else if (state.profile.role === 'verifier') {
+    if (state.profile.isViewer) {
+      ok = true
+    } else if (state.profile.isVerified) {
+      ok = true
+    }
+  }
+
+  if (
+    !state.profile.showBadge &&
+    !state.profile.isViewer &&
+    !(state.viewer.role === 'verifier' && state.viewer.hasIssuedVerification)
+  ) {
+    ok = false
+  }
+
+  return ok
+}
+
+export function VerificationCheckButton({
+  profile,
+  size,
+}: {
+  profile: Shadow<bsky.profile.AnyProfileView>
+  size: 'lg' | 'md' | 'sm'
+}) {
+  const state = useFullVerificationState({
+    profile,
+  })
+
+  if (shouldShowVerificationCheckButton(state)) {
+    return <Badge profile={profile} verificationState={state} size={size} />
+  }
+
+  return null
+}
+
+export function Badge({
+  profile,
+  verificationState: state,
+  size,
+}: {
+  profile: Shadow<bsky.profile.AnyProfileView>
+  verificationState: FullVerificationState
+  size: 'lg' | 'md' | 'sm'
+}) {
+  const t = useTheme()
+  const {_} = useLingui()
+  const verificationsDialogControl = useDialogControl()
+  const verifierDialogControl = useDialogControl()
+  const {gtPhone} = useBreakpoints()
+  let dimensions = 12
+  if (size === 'lg') {
+    dimensions = gtPhone ? 20 : 18
+  } else if (size === 'md') {
+    dimensions = 16
+  }
+
+  const verifiedByHidden = !state.profile.showBadge && state.profile.isViewer
+
+  return (
+    <>
+      <Button
+        label={
+          state.profile.isViewer
+            ? _(msg`View your verifications`)
+            : _(msg`View this user's verifications`)
+        }
+        hitSlop={20}
+        onPress={() => {
+          logger.metric('verification:badge:click', {})
+          if (state.profile.role === 'verifier') {
+            verifierDialogControl.open()
+          } else {
+            verificationsDialogControl.open()
+          }
+        }}
+        style={[]}>
+        {({hovered}) => (
+          <View
+            style={[
+              a.justify_end,
+              a.align_end,
+              a.transition_transform,
+              {
+                width: dimensions,
+                height: dimensions,
+                transform: [
+                  {
+                    scale: hovered ? 1.1 : 1,
+                  },
+                ],
+              },
+            ]}>
+            <VerificationCheck
+              width={dimensions}
+              fill={
+                verifiedByHidden
+                  ? t.atoms.bg_contrast_100.backgroundColor
+                  : state.profile.isVerified
+                  ? t.palette.primary_500
+                  : t.atoms.bg_contrast_100.backgroundColor
+              }
+              verifier={state.profile.role === 'verifier'}
+            />
+          </View>
+        )}
+      </Button>
+
+      <VerificationsDialog
+        control={verificationsDialogControl}
+        profile={profile}
+        verificationState={state}
+      />
+
+      <VerifierDialog
+        control={verifierDialogControl}
+        profile={profile}
+        verificationState={state}
+      />
+    </>
+  )
+}
-- 
cgit 1.4.1

