diff --git a/.gitignore b/.gitignore
index 4ef86cc77b..93e680f355 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@ yarn-error.log*
.env.development.local
.env.test.local
.env.production.local
+.env*
# vercel
.vercel
diff --git a/lang/ct.json b/lang/ct.json
index 1f1a4c7fec..ffb948a80d 100644
--- a/lang/ct.json
+++ b/lang/ct.json
@@ -61,7 +61,7 @@
"component.pro_guide.tips.address.item1": "Comproveu dues vegades que la vostra adreça de moneder sigui correcta per no perdre les vostres donacions.",
"component.pro_guide.tips.address.item2": "Fes servir una adreça de recepció específica per al teu projecte, en lloc d’utilitzar una adreça que fas servir per a altres activitats on-chain. Això millora la transparència i la comptabilitat, i redueix el risc.",
"component.pro_guide.tips.address.item3": "Recomanem utilitzar un moneder de maquinari per millorar la seguretat.",
- "component.pro_guide.tips.address.item4":"Afegir una adreça de recepció a múltiples cadenes augmentarà la teva visibilitat davant possibles donants.",
+ "component.pro_guide.tips.address.item4": "Afegir una adreça de recepció a múltiples cadenes augmentarà la teva visibilitat davant possibles donants.",
"component.pro_guide.tips.address.item5": "Podeu actualitzar les vostres adreces de destinatari en qualsevol moment.",
"component.pro_guide.tips.social_media.item1": "Afegir els teus comptes de xarxes socials permet als teus donants i comunitat connectar-se amb tu i saber què estàs fent!",
"component.pro_guide.tips.social_media.item2": "Els teus comptes estaran enllaçats des de la pàgina del teu projecte a Giveth.",
@@ -288,7 +288,7 @@
"label.copied": "Copiat!",
"label.copy_link": "Copiar enllaç",
"label.copy_the_memo_to_use_in_your_app": "Copia la mnemotècnia per utilitzar a la teva aplicació de cartera.",
-"label.the_recipient_wallet_doesnt_require_a_memo_but_giveth_requires_one": "La cartera del destinatari no requereix cap memo, però Giveth sí que en requereix un per detectar correctament la donació. Assegura’t d’enviar la quantitat correcta de tokens o la teva donació es PERDRÀ!",
+ "label.the_recipient_wallet_doesnt_require_a_memo_but_giveth_requires_one": "La cartera del destinatari no requereix cap memo, però Giveth sí que en requereix un per detectar correctament la donació. Assegura’t d’enviar la quantitat correcta de tokens o la teva donació es PERDRÀ!",
"label.covenant": "conveni",
"label.created_at": "Creat el",
"label.create_a_project": "Crear un projecte",
@@ -935,7 +935,7 @@
"label.save_changes": "Desa els canvis",
"label.save_on_gas_fees": "Estalvia en taxes de gas, canvia de xarxa.",
"label.say_hello_to": "Saluda a...",
-"label.scan_to_donate": "Escaneja el codi QR o copia l’adreça per fer la transferència. Per obtenir millors resultats, utilitza una cartera nativa de Stellar; les donacions enviades directament des d’intercanvis centralitzats poden no ser detectades.",
+ "label.scan_to_donate": "Escaneja el codi QR o copia l’adreça per fer la transferència. Per obtenir millors resultats, utilitza una cartera nativa de Stellar; les donacions enviades directament des d’intercanvis centralitzats poden no ser detectades.",
"label.sdg_impact_fund": "Fons d'impacte SDG",
"label.search": "Cerca",
"label.search_for_a_project_or_a_cause": "Cerca un projecte o una causa a totes les categories",
@@ -1237,7 +1237,7 @@
"label.verify_your_project.modal.three": "procés de verificació ",
"label.verify_your_project.modal.two": "Aquest senzill ",
"label.view": "Veure",
-"label.view_all_projects": "Veure tots els projectes",
+ "label.view_all_projects": "Veure tots els projectes",
"label.view_all_causes": "Veure totes les Causes",
"label.view_details": "Veure detalls",
"label.view_more": "Veure més",
@@ -1899,7 +1899,7 @@
"label.cause.transfer": "Transferència",
"label.cause.congratulations": "Enhorabona",
"label.cause.success_message": "La teva Causa s'ha publicat.",
-"label.cause.ai_powered": "Potenciat per IA",
+ "label.cause.ai_powered": "Potenciat per IA",
"label.cause.please_note_desc": "La teva aportació aquí serà utilitzada per l'agent de donacions amb IA per avaluar i distribuir fons als projectes. Sigues específic sobre l'impacte que vols aconseguir.",
"label.cause.description_required": "Cal introduir una descripció",
"label.cause.cause_all": "Totes les Causes",
@@ -1983,9 +1983,9 @@
"label.cause.transaction_failed_desc_2": "Si us plau, torna enrere i intenta-ho de nou.",
"label.cause.donate_to_cause": "Dona a la causa",
"label.cause.distributed_by_ai": "Distribuït per IA",
-"label.cause.distributed_by_ai_desc": "Les donacions fetes a Causes es canvien per GIV i es distribueixen a projectes basant-se en una rigorosa anàlisi d'IA de la informació del projecte i la seva activitat a les xarxes socials.",
-"label.cause.distributed_by_ai_desc_2": "Les donacions fetes a aquesta Causa es distribueixen als projectes indicats a continuació segons una rigorosa anàlisi d'IA de la informació de cada projecte i la seva activitat a les xarxes socials.",
-"label.cause.this_cause_doesnt_accept_on": "Aquesta causa no accepta",
+ "label.cause.distributed_by_ai_desc": "Les donacions fetes a Causes es canvien per GIV i es distribueixen a projectes basant-se en una rigorosa anàlisi d'IA de la informació del projecte i la seva activitat a les xarxes socials.",
+ "label.cause.distributed_by_ai_desc_2": "Les donacions fetes a aquesta Causa es distribueixen als projectes indicats a continuació segons una rigorosa anàlisi d'IA de la informació de cada projecte i la seva activitat a les xarxes socials.",
+ "label.cause.this_cause_doesnt_accept_on": "Aquesta causa no accepta",
"label.cause.this_token_is_not_supported_by_squid": "Aquest token no és compatible amb el router Squid. Tria un altre token.",
"label.cause.cause_deactivated": "La teva causa ha estat desactivada correctament. Gràcies per utilitzar Giveth.",
"label.cause.go_to_causes": "Anar a Causes",
diff --git a/lang/es.json b/lang/es.json
index 13c4cf1858..69516a39fb 100644
--- a/lang/es.json
+++ b/lang/es.json
@@ -61,7 +61,7 @@
"component.pro_guide.tips.address.item1": "Verifica dos veces que tu dirección de billetera sea correcta para no perder tus donaciones.",
"component.pro_guide.tips.address.item2": "Usa una dirección de recepción específica para tu proyecto, en lugar de utilizar una dirección que empleas para otras actividades on-chain. Esto mejora la transparencia y la contabilidad, y reduce el riesgo.",
"component.pro_guide.tips.address.item3": "Recomendamos usar un monedero de hardware para mejorar la seguridad.",
- "component.pro_guide.tips.address.item4":"Añadir una dirección de recepción en múltiples cadenas aumentará tu visibilidad ante posibles donantes.",
+ "component.pro_guide.tips.address.item4": "Añadir una dirección de recepción en múltiples cadenas aumentará tu visibilidad ante posibles donantes.",
"component.pro_guide.tips.address.item5": "Puedes actualizar tus direcciones de destinatario en cualquier momento.",
"component.pro_guide.tips.social_media.item1": "Agregar tus cuentas de redes sociales permite a tus donantes y comunidad conectarse contigo y saber en qué estás trabajando.",
"component.pro_guide.tips.social_media.item2": "Tus cuentas estarán vinculadas desde la página de tu proyecto en Giveth.",
@@ -286,7 +286,7 @@
"label.copied": "Copiado!",
"label.copy_link": "Copiar Link",
"label.copy_the_memo_to_use_in_your_app": "Copia la mnemotecnia para usar en tu aplicación de billetera.",
-"label.the_recipient_wallet_doesnt_require_a_memo_but_giveth_requires_one": "La billetera del destinatario no requiere un memo, pero Giveth sí requiere uno para detectar correctamente la donación. ¡Asegúrate de enviar la cantidad correcta de tokens o tu donación se PERDERÁ!",
+ "label.the_recipient_wallet_doesnt_require_a_memo_but_giveth_requires_one": "La billetera del destinatario no requiere un memo, pero Giveth sí requiere uno para detectar correctamente la donación. ¡Asegúrate de enviar la cantidad correcta de tokens o tu donación se PERDERÁ!",
"label.covenant": "El convenio",
"label.created_at": "Creación",
"label.create_a_project": "Crea un Proyecto",
@@ -935,7 +935,7 @@
"label.save_changes": "Guardar cambios",
"label.save_on_gas_fees": "Ahorra en tarifas de gas, cambia de red.",
"label.say_hello_to": "Dile hola a...",
-"label.scan_to_donate": "Escanea el código QR o copia la dirección para realizar la transferencia. Para obtener mejores resultados, usa una billetera nativa de Stellar; las donaciones enviadas directamente desde exchanges centralizados pueden no ser detectadas.",
+ "label.scan_to_donate": "Escanea el código QR o copia la dirección para realizar la transferencia. Para obtener mejores resultados, usa una billetera nativa de Stellar; las donaciones enviadas directamente desde exchanges centralizados pueden no ser detectadas.",
"label.sdg_impact_fund": "Fondo de impacto SDG",
"label.search": "Buscar",
"label.search_for_a_project_or_a_cause": "Busca un proyecto o una Causa en todas las categorias",
@@ -1899,7 +1899,7 @@
"label.cause.transfer": "Transferencia",
"label.cause.congratulations": "Enhorabuena",
"label.cause.success_message": "Tu Causa ha sido publicada.",
-"label.cause.ai_powered": "Potenciado por IA",
+ "label.cause.ai_powered": "Potenciado por IA",
"label.cause.please_note_desc": "Tu aportación aquí será utilizada por el agente de donaciones con IA para evaluar y distribuir fondos a los proyectos. Sé específico sobre el impacto que deseas lograr.",
"label.cause.description_required": "La descripción es obligatoria",
"label.cause.cause_all": "Todas las Causas",
@@ -1983,9 +1983,9 @@
"label.cause.transaction_failed_desc_2": "Por favor vuelve atrás e intenta de nuevo.",
"label.cause.donate_to_cause": "Donar a la Causa",
"label.cause.distributed_by_ai": "Distribuido por IA",
-"label.cause.distributed_by_ai_desc": "Las donaciones hechas a Causas se cambian por GIV y se distribuyen a proyectos basándose en un riguroso análisis de IA de la información del proyecto y su actividad en redes sociales.",
+ "label.cause.distributed_by_ai_desc": "Las donaciones hechas a Causas se cambian por GIV y se distribuyen a proyectos basándose en un riguroso análisis de IA de la información del proyecto y su actividad en redes sociales.",
"label.cause.distributed_by_ai_desc_2": "Las donaciones hechas a esta Causa se distribuyen a los proyectos indicados abajo según un riguroso análisis de IA de la información de cada proyecto y su actividad en redes sociales.",
-"label.cause.this_cause_doesnt_accept_on": "Esta Causa no acepta",
+ "label.cause.this_cause_doesnt_accept_on": "Esta Causa no acepta",
"label.cause.this_token_is_not_supported_by_squid": "Este token no es compatible con el router Squid. Elige otro token.",
"label.cause.cause_deactivated": "Tu Causa fue desactivada correctamente. Gracias por usar Giveth.",
"label.cause.go_to_causes": "Ir a Causas",
diff --git a/next.config.js b/next.config.js
index b3e47382a0..5721c46328 100644
--- a/next.config.js
+++ b/next.config.js
@@ -16,6 +16,8 @@ const locales = ['en', 'ct', 'es'];
const moduleExports = withBundleAnalyzer({
// Your existing module.exports
reactStrictMode: true,
+ // Transpile the Farcaster SDK for proper ESM support
+ transpilePackages: ['@farcaster/miniapp-sdk', '@farcaster/miniapp-core'],
images: {
remotePatterns: [
{ protocol: 'https', port: '', hostname: 'placekitten.com' },
@@ -133,7 +135,20 @@ const moduleExports = withBundleAnalyzer({
'https://nounspace.com',
'https://www.nounspace.com',
];
- const frameAncestors = ["'self'", safe, ...nounspace].join(' ');
+ // Base Mini App and Farcaster clients
+ const baseApp = [
+ 'https://base.org',
+ 'https://www.base.org',
+ 'https://base.dev',
+ 'https://www.base.dev',
+ 'https://warpcast.com',
+ 'https://www.warpcast.com',
+ 'https://www.farcaster.xyz',
+ 'https://farcaster.xyz',
+ ];
+ const frameAncestors = ["'self'", safe, ...nounspace, ...baseApp].join(
+ ' ',
+ );
// Declare additional consts and include them in frameAncestors to enable additional domains to embed Giveth pages in iframes.
return [
{
@@ -186,6 +201,26 @@ const moduleExports = withBundleAnalyzer({
},
],
},
+ {
+ // Adding CORS headers for /.well-known/farcaster.json (Base Mini App manifest)
+ source: '/.well-known/farcaster.json',
+ locale: false,
+ headers: [
+ {
+ key: 'Access-Control-Allow-Origin',
+ value: '*',
+ },
+ { key: 'Access-Control-Allow-Methods', value: 'GET' },
+ {
+ key: 'Access-Control-Allow-Headers',
+ value: 'X-Requested-With, content-type, Authorization',
+ },
+ {
+ key: 'Cache-Control',
+ value: 'public, max-age=3600',
+ },
+ ],
+ },
];
},
});
diff --git a/package.json b/package.json
index a272517f68..42a53346aa 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,10 @@
},
"dependencies": {
"@apollo/client": "^3.11.8",
+ "@coinbase/onchainkit": "^1.1.2",
"@divvi/referral-sdk": "^1.0.0",
+ "@farcaster/miniapp-sdk": "^0.2.1",
+ "@farcaster/miniapp-wagmi-connector": "^1.1.0",
"@giveth/ui-design-system": "^1.11.36",
"@next/third-parties": "^14.2.5",
"@react-google-maps/api": "^2.19.3",
diff --git a/pages/_app.tsx b/pages/_app.tsx
index d0cd2539b4..23e52ec6d1 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { createWeb3Modal } from '@web3modal/wagmi/react';
import Head from 'next/head';
+import dynamic from 'next/dynamic';
import { IntlProvider } from 'react-intl';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Toaster } from 'react-hot-toast';
@@ -42,6 +43,22 @@ import MaintenanceIndex from '@/components/views/Errors/MaintenanceIndex';
import { SolanaProvider } from '@/providers/solanaWalletProvider';
import type { AppProps } from 'next/app';
+// Dynamically import MiniKitProvider with SSR disabled to prevent SDK issues
+const MiniKitProvider = dynamic(
+ () =>
+ import('@/components/MiniKitProvider').then(mod => mod.MiniKitProvider),
+ { ssr: false },
+);
+
+// Dynamically import FarcasterAutoConnect to handle automatic wallet connection in mini app
+const FarcasterAutoConnect = dynamic(
+ () =>
+ import('@/components/FarcasterAutoConnect').then(
+ mod => mod.FarcasterAutoConnect,
+ ),
+ { ssr: false },
+);
+
if (!isProduction) {
// Adds messages only in a dev environment
loadDevMessages();
@@ -174,54 +191,63 @@ function MyApp({ Component, pageProps }: AppProps) {
name='viewport'
content='width=device-width, initial-scale=1.0'
/>
+
-
-
-
-
-
-
-
-
- {isMaintenanceMode ? (
-
- ) : (
- <>
-
-
-
-
-
- {isGIVeconomyRoute(
- router.route,
- ) && }
- {(pageProps as any)
- .errorStatus ? (
-
- ) : (
-
- )}
- {/* {process.env.NEXT_PUBLIC_ENV !==
+
+
+
+
+
+
+
+
+ {/* Auto-connect to Farcaster wallet when in mini app */}
+
+
+ {isMaintenanceMode ? (
+
+ ) : (
+ <>
+
+
+
+
+
+ {isGIVeconomyRoute(
+ router.route,
+ ) && }
+ {(pageProps as any)
+ .errorStatus ? (
+
+ ) : (
+
+ )}
+ {/* {process.env.NEXT_PUBLIC_ENV !==
'production' && (
)} */}
-
-
-
- >
- )}
-
-
-
-
-
-
-
-
+
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
diff --git a/pages/api/miniapp/webhook.ts b/pages/api/miniapp/webhook.ts
new file mode 100644
index 0000000000..ff29b94dc9
--- /dev/null
+++ b/pages/api/miniapp/webhook.ts
@@ -0,0 +1,102 @@
+import type { NextApiRequest, NextApiResponse } from 'next';
+
+/**
+ * Base Mini App Webhook Handler
+ *
+ * This endpoint receives webhook notifications from the Base/Farcaster platform.
+ * Common webhook events include:
+ * - frame_added: When a user adds the mini app
+ * - frame_removed: When a user removes the mini app
+ * - notifications_enabled: When a user enables notifications
+ * - notifications_disabled: When a user disables notifications
+ *
+ * @see https://docs.base.org/mini-apps/features/notifications
+ */
+
+interface WebhookPayload {
+ event: string;
+ data: {
+ fid?: number;
+ notificationDetails?: {
+ url: string;
+ token: string;
+ };
+ [key: string]: unknown;
+ };
+}
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse,
+) {
+ // Only accept POST requests
+ if (req.method !== 'POST') {
+ res.setHeader('Allow', ['POST']);
+ return res.status(405).json({ error: 'Method not allowed' });
+ }
+
+ try {
+ const payload = req.body as WebhookPayload;
+
+ console.log('[MiniApp Webhook] Received event:', payload.event);
+ console.log(
+ '[MiniApp Webhook] Payload:',
+ JSON.stringify(payload, null, 2),
+ );
+
+ // Handle different webhook events
+ switch (payload.event) {
+ case 'frame_added':
+ // User added the mini app
+ console.log(
+ '[MiniApp Webhook] User added mini app, FID:',
+ payload.data?.fid,
+ );
+ // TODO: Track user addition, store notification details if provided
+ break;
+
+ case 'frame_removed':
+ // User removed the mini app
+ console.log(
+ '[MiniApp Webhook] User removed mini app, FID:',
+ payload.data?.fid,
+ );
+ // TODO: Clean up user data if needed
+ break;
+
+ case 'notifications_enabled':
+ // User enabled notifications
+ console.log(
+ '[MiniApp Webhook] Notifications enabled, FID:',
+ payload.data?.fid,
+ );
+ // TODO: Store notification URL and token for sending notifications
+ if (payload.data?.notificationDetails) {
+ // Store: payload.data.notificationDetails.url
+ // Store: payload.data.notificationDetails.token
+ }
+ break;
+
+ case 'notifications_disabled':
+ // User disabled notifications
+ console.log(
+ '[MiniApp Webhook] Notifications disabled, FID:',
+ payload.data?.fid,
+ );
+ // TODO: Remove stored notification credentials
+ break;
+
+ default:
+ console.log(
+ '[MiniApp Webhook] Unknown event type:',
+ payload.event,
+ );
+ }
+
+ // Acknowledge receipt
+ return res.status(200).json({ success: true });
+ } catch (error) {
+ console.error('[MiniApp Webhook] Error processing webhook:', error);
+ return res.status(500).json({ error: 'Internal server error' });
+ }
+}
diff --git a/pages/index.tsx b/pages/index.tsx
index 14efe29d98..8742fc9ba5 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -1,11 +1,9 @@
-import { GetStaticProps } from 'next/types';
+import type { FC } from 'react';
-import HomeIndex from '@/components/views/homepage/HomeIndex';
-import { client } from '@/apollo/apolloClient';
-import { ICampaign, IProjectUpdateWithProject } from '@/apollo/types/types';
-import { homeMetatags } from '@/content/metatags';
-import { GeneralMetatags } from '@/components/Metatag';
-import { FETCH_HOMEPAGE_DATA_REDUCED } from '@/apollo/gql/gqlHomePage';
+import type {
+ ICampaign,
+ IProjectUpdateWithProject,
+} from '@/apollo/types/types';
export interface IHomeRoute {
projectsPerDate: { total: number };
@@ -15,43 +13,8 @@ export interface IHomeRoute {
campaigns: ICampaign[];
}
-export const HOME_QUERY_VARIABLES = {
- take: 50,
- takeLatestUpdates: 10,
- skipLatestUpdates: 0,
- fromDate: '2021-01-01',
- toDate: new Date().toISOString().split('T')[0], // Today's date
- connectedWalletUserId: null,
-};
-
-const HomeRoute = (props: IHomeRoute) => {
- return (
- <>
-
-
- >
- );
-};
-
-export const getStaticProps: GetStaticProps = async () => {
- const { data } = await client.query({
- query: FETCH_HOMEPAGE_DATA_REDUCED,
- variables: HOME_QUERY_VARIABLES,
- fetchPolicy: 'no-cache',
- context: {
- skipAuth: true,
- },
- });
- return {
- props: {
- projectsPerDate: data.projectsPerDate,
- totalDonorsCountPerDate: data.totalDonorsCountPerDate,
- donationsTotalUsdPerDate: data.donationsTotalUsdPerDate,
- latestUpdates: data.projectUpdates.projectUpdates,
- campaigns: data.campaigns,
- },
- revalidate: 600,
- };
+const HomeRoute: FC = () => {
+ return