Merge branch 'main' into veganbeef/fix-siwn

This commit is contained in:
veganbeef
2025-07-15 09:29:35 -07:00
72 changed files with 6224 additions and 1046 deletions

View File

@@ -1,12 +1,12 @@
'use client';
import { useCallback, useState } from "react";
import { useMiniApp } from "@neynar/react";
import { ShareButton } from "../Share";
import { Button } from "../Button";
import { SignIn } from "../wallet/SignIn";
import { type Haptics } from "@farcaster/miniapp-sdk";
import { APP_URL } from "~/lib/constants";
import { useCallback, useState } from 'react';
import { type Haptics } from '@farcaster/miniapp-sdk';
import { useMiniApp } from '@neynar/react';
import { APP_URL } from '~/lib/constants';
import { Button } from '../Button';
import { ShareButton } from '../Share';
import { SignIn } from '../wallet/SignIn';
// Optional import for NeynarAuthButton - may not exist in all templates
let NeynarAuthButton: React.ComponentType | null = null;
@@ -61,7 +61,7 @@ export function ActionsTab() {
* @returns Promise that resolves when the notification is sent or fails
*/
const sendFarcasterNotification = useCallback(async () => {
setNotificationState((prev) => ({ ...prev, sendStatus: '' }));
setNotificationState(prev => ({ ...prev, sendStatus: '' }));
if (!notificationDetails || !context) {
return;
}
@@ -76,22 +76,22 @@ export function ActionsTab() {
}),
});
if (response.status === 200) {
setNotificationState((prev) => ({ ...prev, sendStatus: 'Success' }));
setNotificationState(prev => ({ ...prev, sendStatus: 'Success' }));
return;
} else if (response.status === 429) {
setNotificationState((prev) => ({
setNotificationState(prev => ({
...prev,
sendStatus: 'Rate limited',
}));
return;
}
const responseText = await response.text();
setNotificationState((prev) => ({
setNotificationState(prev => ({
...prev,
sendStatus: `Error: ${responseText}`,
}));
} catch (error) {
setNotificationState((prev) => ({
setNotificationState(prev => ({
...prev,
sendStatus: `Error: ${error}`,
}));
@@ -108,11 +108,11 @@ export function ActionsTab() {
if (context?.user?.fid) {
const userShareUrl = `${APP_URL}/share/${context.user.fid}`;
await navigator.clipboard.writeText(userShareUrl);
setNotificationState((prev) => ({ ...prev, shareUrlCopied: true }));
setNotificationState(prev => ({ ...prev, shareUrlCopied: true }));
setTimeout(
() =>
setNotificationState((prev) => ({ ...prev, shareUrlCopied: false })),
2000
setNotificationState(prev => ({ ...prev, shareUrlCopied: false })),
2000,
);
}
}, [context?.user?.fid]);
@@ -133,16 +133,16 @@ export function ActionsTab() {
// --- Render ---
return (
<div className='space-y-3 px-6 w-full max-w-md mx-auto'>
<div className="space-y-3 px-6 w-full max-w-md mx-auto">
{/* Share functionality */}
<ShareButton
buttonText='Share Mini App'
buttonText="Share Mini App"
cast={{
text: 'Check out this awesome frame @1 @2 @3! 🚀🪐',
bestFriends: true,
embeds: [`${APP_URL}/share/${context?.user?.fid || ''}`]
embeds: [`${APP_URL}/share/${context?.user?.fid || ''}`],
}}
className='w-full'
className="w-full"
/>
{/* Authentication */}
@@ -156,25 +156,25 @@ export function ActionsTab() {
onClick={() =>
actions.openUrl('https://www.youtube.com/watch?v=dQw4w9WgXcQ')
}
className='w-full'
className="w-full"
>
Open Link
</Button>
<Button onClick={actions.addMiniApp} disabled={added} className='w-full'>
<Button onClick={actions.addMiniApp} disabled={added} className="w-full">
Add Mini App to Client
</Button>
{/* Notification functionality */}
{notificationState.sendStatus && (
<div className='text-sm w-full'>
<div className="text-sm w-full">
Send notification result: {notificationState.sendStatus}
</div>
)}
<Button
onClick={sendFarcasterNotification}
disabled={!notificationDetails}
className='w-full'
className="w-full"
>
Send notification
</Button>
@@ -183,24 +183,24 @@ export function ActionsTab() {
<Button
onClick={copyUserShareUrl}
disabled={!context?.user?.fid}
className='w-full'
className="w-full"
>
{notificationState.shareUrlCopied ? 'Copied!' : 'Copy share URL'}
</Button>
{/* Haptic feedback controls */}
<div className='space-y-2'>
<label className='block text-sm font-medium text-gray-700 dark:text-gray-300'>
<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
Haptic Intensity
</label>
<select
value={selectedHapticIntensity}
onChange={(e) =>
onChange={e =>
setSelectedHapticIntensity(
e.target.value as Haptics.ImpactOccurredType
e.target.value as Haptics.ImpactOccurredType,
)
}
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-primary'
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-primary"
>
<option value={'light'}>Light</option>
<option value={'medium'}>Medium</option>
@@ -208,7 +208,7 @@ export function ActionsTab() {
<option value={'soft'}>Soft</option>
<option value={'rigid'}>Rigid</option>
</select>
<Button onClick={triggerHapticFeedback} className='w-full'>
<Button onClick={triggerHapticFeedback} className="w-full">
Trigger Haptic Feedback
</Button>
</div>