Skip to content

Commit 91b23d7

Browse files
committed
feat: add dynamic basename handling
1 parent dab2db3 commit 91b23d7

File tree

5 files changed

+137
-3
lines changed

5 files changed

+137
-3
lines changed

.env.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
VITE_REOWN_PROJECT_ID=31dfd450a68758ef69ab89125f2b6c4b
2-
VITE_ROLLBAR_ACCESS_TOKEN=
2+
VITE_ROLLBAR_ACCESS_TOKEN=
3+
4+
VITE_VERCEL_ENV=development
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {
2+
WEB3MAIL_IDAPPS_WHITELIST_SC,
3+
WEB3TELEGRAM_IDAPPS_WHITELIST_SC,
4+
} from '@/config/config';
5+
import { Contact as Web3mailContact } from '@iexec/web3mail';
6+
import { Contact as Web3telegramContact } from '@iexec/web3telegram';
7+
import { useQuery } from '@tanstack/react-query';
8+
import { Link } from 'react-router-dom';
9+
import { LoadingSpinner } from '@/components/LoadingSpinner';
10+
import { Button } from '@/components/ui/button';
11+
import { getDataProtectorCoreClient } from '@/externals/iexecSdkClient';
12+
import useUserStore from '@/stores/useUser.store';
13+
import { cn } from '@/utils/style.utils';
14+
15+
interface ContactItemProps {
16+
contact: (Web3telegramContact | Web3mailContact) & {
17+
contactType: 'mail' | 'telegram';
18+
};
19+
}
20+
21+
const fetchContactDetails = async (
22+
contact: (Web3telegramContact | Web3mailContact) & {
23+
contactType: 'mail' | 'telegram';
24+
},
25+
userAddress: string
26+
) => {
27+
const dataProtectorCore = await getDataProtectorCoreClient();
28+
29+
const contactProtectedData = await dataProtectorCore.getProtectedData({
30+
protectedDataAddress: contact.address,
31+
});
32+
33+
const grantedAccess = await dataProtectorCore.getGrantedAccess({
34+
protectedData: contact.address,
35+
authorizedUser: userAddress,
36+
authorizedApp:
37+
contact.contactType === 'mail'
38+
? WEB3MAIL_IDAPPS_WHITELIST_SC
39+
: WEB3TELEGRAM_IDAPPS_WHITELIST_SC,
40+
});
41+
42+
return {
43+
...contactProtectedData[0],
44+
contactType: contact.contactType,
45+
volume: grantedAccess.grantedAccess[0].volume,
46+
};
47+
};
48+
49+
export default function ContactItem({ contact }: ContactItemProps) {
50+
const { address: userAddress } = useUserStore();
51+
52+
const {
53+
data: contactDetails,
54+
isLoading,
55+
isError,
56+
} = useQuery({
57+
queryKey: ['contactDetails', contact.address, userAddress],
58+
queryFn: () => fetchContactDetails(contact, userAddress as string),
59+
enabled: !!userAddress,
60+
refetchOnWindowFocus: false,
61+
staleTime: 5 * 60 * 1000, // 5 minutes
62+
});
63+
64+
if (isError) {
65+
console.error('Error loading contact details:', contact.address);
66+
return <p>Error loading contact details</p>;
67+
}
68+
69+
return (
70+
<div
71+
className={cn(
72+
'bg-grey-50 even:*:bg-grey-800 *:border-grey-600 contents text-sm *:flex *:h-full *:items-center *:border-t *:px-5 *:py-3'
73+
)}
74+
>
75+
<div className="truncate">
76+
{isLoading ? <LoadingSpinner /> : contactDetails?.name || '(No name)'}
77+
</div>
78+
<div className="truncate">
79+
<span className="truncate whitespace-nowrap">{contact.address}</span>
80+
</div>
81+
<div className="truncate">
82+
<span className="truncate whitespace-nowrap">
83+
{contact.owner === userAddress
84+
? `(Mine) ${contact.owner}`
85+
: contact.owner}
86+
</span>
87+
</div>
88+
<div className="truncate">
89+
{isLoading ? <LoadingSpinner /> : contactDetails?.volume || 'N/A'}
90+
</div>
91+
<div className="text-primary truncate uppercase">
92+
{contact.contactType}
93+
</div>
94+
<div className="justify-end">
95+
<Button asChild variant="discreet_outline">
96+
<Link to={`/contacts/${contact.address}/send-message`}>Send</Link>
97+
</Button>
98+
</div>
99+
</div>
100+
);
101+
}

src/router.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Resources from '@/views/resources';
22
import { createBrowserRouter, Navigate } from 'react-router-dom';
33
import MainLayout from './layouts/MainLayout.tsx';
4+
import { getBasename } from './utils/getBasename.ts';
45
import ContactList from './views/contact/contactList.tsx';
56
import SendMessage from './views/contact/sendMessage.tsx';
67
import AddProtectedData from './views/myData/addProtectedData.tsx';
@@ -45,6 +46,6 @@ export const router = createBrowserRouter(
4546
},
4647
],
4748
{
48-
basename: '/web3messaging',
49+
basename: getBasename(),
4950
}
5051
);

src/utils/getBasename.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const getBasename = (): string => {
2+
const vercelEnv = import.meta.env.VITE_VERCEL_ENV || process.env.VERCEL_ENV;
3+
4+
// Vercel production
5+
if (vercelEnv === 'production') {
6+
return '/web3messaging';
7+
}
8+
9+
// Vercel preview/staging
10+
if (vercelEnv === 'preview') {
11+
return '/';
12+
}
13+
14+
// Local development
15+
return '/web3messaging';
16+
};

vite.config.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,22 @@ import tailwindcss from '@tailwindcss/vite'
55

66
export default defineConfig(({ mode }) => {
77
const env = loadEnv(mode, process.cwd(), '');
8+
9+
const getBase = () => {
10+
// Vercel production
11+
if (env.VERCEL_ENV === 'production') {
12+
return '/web3messaging';
13+
}
14+
// Vercel preview/staging
15+
if (env.VERCEL_ENV === 'preview') {
16+
return '/';
17+
}
18+
// local development
19+
return '/web3messaging';
20+
};
21+
822
return {
9-
base: "/web3messaging",
23+
base: getBase(),
1024
define: {
1125
'process.env.NEXT_PUBLIC_SECURE_SITE_ORIGIN': JSON.stringify(
1226
env.NEXT_PUBLIC_SECURE_SITE_ORIGIN || 'https://secure.walletconnect.org'

0 commit comments

Comments
 (0)