Skip to content

Commit d2179b8

Browse files
Merge pull request #700 from ResearchHub/verify-idetity-modal-updates
Verify Identity Modal udpates
2 parents b2b7780 + ac28567 commit d2179b8

11 files changed

Lines changed: 94 additions & 47 deletions

File tree

app/expert-finder/library/components/LibraryPageContent.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { useState } from 'react';
44
import { useRouter } from 'next/navigation';
55
import { Alert } from '@/components/ui/Alert';
6+
import { Breadcrumbs } from '@/components/ui/Breadcrumbs';
67
import { PaginationButton } from '@/components/ui/PaginationButton';
78
import { useExpertSearches } from '@/hooks/useExpertFinder';
89
import { useScreenSize } from '@/hooks/useScreenSize';
@@ -115,9 +116,7 @@ export function LibraryPageContent() {
115116
<div className="w-full max-w-5xl mx-auto px-4 py-8">
116117
<div className="flex flex-wrap items-center justify-between gap-4 mb-6">
117118
<div>
118-
<h2 className="text-base font-semibold text-gray-900 mb-2 sm:!text-lg md:!text-2xl">
119-
Library
120-
</h2>
119+
<Breadcrumbs items={[{ label: 'Library' }]} className="mb-2" />
121120
<p className="text-sm text-gray-600">View your expert search history.</p>
122121
</div>
123122
{searches.length > 0 && (

app/expert-finder/templates/components/TemplatesPageContent.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
55
import { Plus } from 'lucide-react';
66
import Link from 'next/link';
77
import { Alert } from '@/components/ui/Alert';
8+
import { Breadcrumbs } from '@/components/ui/Breadcrumbs';
89
import { Button } from '@/components/ui/Button';
910
import { PaginationButton } from '@/components/ui/PaginationButton';
1011
import { useSavedTemplates } from '@/hooks/useExpertFinder';
@@ -115,9 +116,7 @@ export function TemplatesPageContent() {
115116
<div className="w-full max-w-5xl mx-auto px-4 py-8">
116117
<div className="flex flex-wrap items-center justify-between gap-4 mb-6">
117118
<div>
118-
<h2 className="text-base font-semibold text-gray-900 mb-2 sm:!text-lg md:!text-2xl">
119-
Templates
120-
</h2>
119+
<Breadcrumbs items={[{ label: 'Templates' }]} className="mb-2" />
121120
<p className="text-sm text-gray-600">
122121
Save your contact details and outreach context to reuse when generating emails.
123122
</p>

app/layouts/topbar/pageRoutes.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
faGrid3 as faGrid3Light,
77
faMagnifyingGlass,
88
} from '@fortawesome/pro-light-svg-icons';
9-
import { ChartNoAxesColumnIncreasing, Shield, Hash } from 'lucide-react';
9+
import { ChartNoAxesColumnIncreasing, Shield, Hash, Users } from 'lucide-react';
1010
import Image from 'next/image';
1111
import { Icon } from '@/components/ui/icons';
1212
import { getTopicEmoji } from '@/components/Topic/TopicEmojis';
@@ -123,6 +123,13 @@ const ROUTE_RULES: RouteRule[] = [
123123
icon: <Shield size={24} className="text-gray-900" />,
124124
}),
125125
},
126+
{
127+
match: (p) => p === '/expert-finder' || p.startsWith('/expert-finder/'),
128+
getInfo: () => ({
129+
title: 'Expert Finder',
130+
icon: <Users size={24} className="text-gray-900" />,
131+
}),
132+
},
126133
{
127134
match: (p) => p.startsWith('/dashboard'),
128135
getInfo: () => ({

components/menus/UserMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,14 @@ export default function UserMenu({
231231
<div
232232
className="px-6 py-2 hover:bg-gray-50"
233233
onClick={() => {
234-
//TODO call the method from the context
235234
setMenuOpenState(false);
235+
openVerificationModal();
236236
}}
237237
onKeyDown={(e) => {
238238
if (e.key === 'Enter' || e.key === ' ') {
239239
e.preventDefault();
240-
//TODO call the method from the context
241240
setMenuOpenState(false);
241+
openVerificationModal();
242242
}
243243
}}
244244
tabIndex={0}

components/modals/Verification/AddPublicationsForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ export function AddPublicationsForm({
318318
)}
319319
</div>
320320

321-
<div className="space-y-4 max-h-[400px] overflow-y-auto">
321+
<div className="space-y-4 max-h-[320px] overflow-y-auto">
322322
{(data?.works || []).map((publication) => (
323323
<div
324324
key={publication.id}

components/modals/Verification/VerificationWithPersonaStep.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ const PersonaReact = dynamic(() => import('persona-react'), {
1414

1515
export interface VerificationWithPersonaStepProps {
1616
onVerificationStatusChange?: (status: 'success' | 'failed') => void;
17+
templateId?: string | null;
1718
}
1819

1920
export function VerificationWithPersonaStep({
2021
onVerificationStatusChange,
22+
templateId,
2123
}: VerificationWithPersonaStepProps): React.JSX.Element {
2224
const [isPersonaLoaded, setIsPersonaLoaded] = useState(false);
2325
const { user } = useUser();
@@ -80,7 +82,7 @@ export function VerificationWithPersonaStep({
8082
<div className={isPersonaLoaded ? '' : 'hidden'}>
8183
<PersonaReact
8284
environmentId={process.env.NEXT_PUBLIC_PERSONA_ENVIRONMENT_ID}
83-
templateId={process.env.NEXT_PUBLIC_PERSONA_TEMPLATE_ID}
85+
templateId={templateId ?? process.env.NEXT_PUBLIC_PERSONA_TEMPLATE_ID}
8486
referenceId={`${user.id}`}
8587
onReady={() => {
8688
setIsPersonaLoaded(true);

components/modals/VerifyIdentityModal.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,10 @@ export function VerifyIdentityModal({
5555

5656
useEffect(() => {
5757
if (isOpen) {
58-
setCurrentStep(initialStep);
59-
} else {
60-
setCurrentStep(initialStep);
58+
setCurrentStep(context === 'publish' ? 'IDENTITY' : initialStep);
59+
setPublicationsSubstep('DOI');
6160
}
62-
}, [isOpen, initialStep]);
61+
}, [isOpen, initialStep, context]);
6362

6463
const handleNext = () => {
6564
if (currentStep === 'INTRO') {
@@ -194,6 +193,11 @@ export function VerifyIdentityModal({
194193
return (
195194
<VerificationWithPersonaStep
196195
onVerificationStatusChange={handleVerificationStatusChange}
196+
templateId={
197+
isPublishContext
198+
? process.env.NEXT_PUBLIC_PERSONA_TEMPLATE_ID_PUBLISH_FLOW
199+
: undefined
200+
}
197201
/>
198202
);
199203

@@ -394,13 +398,20 @@ export function VerifyIdentityModal({
394398
leaveFrom="opacity-100 scale-100"
395399
leaveTo="opacity-0 scale-95"
396400
>
397-
<Dialog.Panel className="w-full max-w-2xl transform overflow-hidden rounded-2xl bg-white text-left align-middle shadow-xl transition-all">
401+
<Dialog.Panel
402+
className={`w-full transform overflow-hidden rounded-2xl bg-white text-left align-middle shadow-xl transition-all ${currentStep === 'IDENTITY' ? 'max-w-[400px]' : 'max-w-2xl'}`}
403+
>
398404
<div className="relative">
399405
{/* Header with close button - only show for non-INTRO steps */}
400406
{currentStep !== 'INTRO' && (
401-
<div className="border-b border-gray-200 px-6 py-4 flex items-center justify-between">
407+
<div
408+
className={`border-b border-gray-200 px-6 py-4 flex items-center justify-between ${currentStep === 'IDENTITY' ? 'fixed top-0 left-0 right-0 !border-0 ml-20' : ''}`}
409+
>
402410
<div className="flex items-center">
403-
<Dialog.Title as="h3" className="text-lg font-medium text-gray-900">
411+
<Dialog.Title
412+
as="h3"
413+
className={`text-lg font-medium text-gray-900 ${currentStep === 'IDENTITY' ? 'hidden' : ''}`}
414+
>
404415
Verify Identity
405416
</Dialog.Title>
406417
</div>

components/ui/ProgressStepper.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,28 @@ export function ProgressStepper({
4242
)}
4343
onClick={() => isClickable && onStepClick(step.id)}
4444
>
45-
<div
46-
className={cn(
47-
'flex items-center justify-center w-8 h-8 rounded-full shrink-0',
48-
isActive
49-
? 'bg-primary-100 text-primary-600 border-2 border-primary-500'
50-
: isCompleted
51-
? 'bg-primary-500 text-white'
52-
: 'bg-gray-100 text-gray-500'
53-
)}
54-
>
55-
{step.icon || (isCompleted ? <CheckIcon className="w-4 h-4" /> : index + 1)}
45+
<div className="flex !flex-col !items-center md:!flex-row md:!items-center !shrink-0">
46+
<div
47+
className={cn(
48+
'flex items-center justify-center !w-8 !h-8 rounded-full !shrink-0',
49+
isActive
50+
? 'bg-primary-100 text-primary-600 border-2 border-primary-500'
51+
: isCompleted
52+
? 'bg-primary-500 text-white'
53+
: 'bg-gray-100 text-gray-500'
54+
)}
55+
>
56+
{step.icon || (isCompleted ? <CheckIcon className="w-4 h-4" /> : index + 1)}
57+
</div>
58+
<span
59+
className={cn(
60+
'!mt-1 !ml-0 !text-center md:!mt-0 md:!ml-2 md:!text-left text-sm font-medium whitespace-nowrap',
61+
isActive ? 'text-primary-600' : isCompleted ? 'text-gray-900' : 'text-gray-500'
62+
)}
63+
>
64+
{step.label}
65+
</span>
5666
</div>
57-
<span
58-
className={cn(
59-
'ml-2 text-sm font-medium whitespace-nowrap',
60-
isActive ? 'text-primary-600' : isCompleted ? 'text-gray-900' : 'text-gray-500'
61-
)}
62-
>
63-
{step.label}
64-
</span>
6567
{index < steps.length - 1 && (
6668
<div
6769
className={cn(

contexts/UserContext.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interface UserContextType {
1212
user: User | null;
1313
isLoading: boolean;
1414
error: Error | null;
15-
refreshUser: () => Promise<User | null>;
15+
refreshUser: (options?: { silent?: boolean }) => Promise<User | null>;
1616
}
1717

1818
const UserContext = createContext<UserContextType | null>(null);
@@ -24,15 +24,15 @@ export function UserProvider({ children }: { children: ReactNode }) {
2424
const [error, setError] = useState<Error | null>(null);
2525
const [isAnalyticsInitialized, setIsAnalyticsInitialized] = useState(false);
2626

27-
const fetchUserData = async (): Promise<User | null> => {
27+
const fetchUserData = async (silent = false): Promise<User | null> => {
2828
if (!session?.authToken) {
2929
setUser(null);
30-
setIsLoading(false);
30+
if (!silent) setIsLoading(false);
3131
return null;
3232
}
3333

3434
try {
35-
setIsLoading(true);
35+
if (!silent) setIsLoading(true);
3636
const userData = await AuthService.fetchUserData(session.authToken);
3737
const fetchedUser = userData.results[0] || null;
3838
setUser(fetchedUser);
@@ -43,16 +43,15 @@ export function UserProvider({ children }: { children: ReactNode }) {
4343
await AuthSharingService.signOutFromBothApps();
4444
}
4545
}
46-
setError(err instanceof Error ? err : new Error('Failed to load user data'));
46+
if (!silent) setError(err instanceof Error ? err : new Error('Failed to load user data'));
4747
return null;
4848
} finally {
49-
setIsLoading(false);
49+
if (!silent) setIsLoading(false);
5050
}
5151
};
5252

53-
// Refresh function that can be called from components
54-
const refreshUser = async (): Promise<User | null> => {
55-
return fetchUserData();
53+
const refreshUser = async (options?: { silent?: boolean }): Promise<User | null> => {
54+
return fetchUserData(options?.silent ?? false);
5655
};
5756

5857
// Effect to load user data when session changes

contexts/VerificationContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function VerificationProvider({ children }: { children: React.ReactNode }
3333

3434
const closeVerificationModal = useCallback(async () => {
3535
setIsModalOpen(false);
36-
const freshUser = await refreshUser();
36+
const freshUser = await refreshUser({ silent: true });
3737
if (freshUser?.isVerified && pendingCallbackRef.current) {
3838
pendingCallbackRef.current();
3939
}

0 commit comments

Comments
 (0)