refactor: convert forwardRef components to function components for consistency
This commit is contained in:
@@ -241,7 +241,7 @@ export function ActivityFeed({typeFilter, dateRangeDays = 30, contactId}: Activi
|
||||
<div className="space-y-4">
|
||||
{upcomingActivities.map((activity, index) => (
|
||||
<div key={`${activity.id}-${index}`}>
|
||||
<ActivityItem activity={activity} isUpcoming={true} />
|
||||
<ActivityItem activity={activity} status="upcoming" />
|
||||
{index < upcomingActivities.length - 1 && <div className="border-t border-neutral-100 my-4" />}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -110,7 +110,7 @@ function isEmailActivity(type: string): boolean {
|
||||
|
||||
interface ActivityItemProps {
|
||||
activity: Activity;
|
||||
isUpcoming?: boolean;
|
||||
status?: 'upcoming' | 'completed';
|
||||
}
|
||||
|
||||
interface ActivityConfig {
|
||||
@@ -342,11 +342,12 @@ function getActivityConfig(activity: Activity): ActivityConfig {
|
||||
}
|
||||
}
|
||||
|
||||
export const ActivityItem = memo(function ActivityItem({activity, isUpcoming = false}: ActivityItemProps) {
|
||||
export const ActivityItem = memo(function ActivityItem({activity, status = 'completed'}: ActivityItemProps) {
|
||||
const [showPreviewModal, setShowPreviewModal] = useState(false);
|
||||
const config = getActivityConfig(activity);
|
||||
const Icon = config.icon;
|
||||
const timestamp = new Date(activity.timestamp);
|
||||
const isUpcoming = status === 'upcoming';
|
||||
const relativeTime = isUpcoming ? getUpcomingTime(timestamp) : getRelativeTime(timestamp);
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,7 +9,6 @@ interface ApiKeyDisplayProps {
|
||||
description?: string;
|
||||
isSecret?: boolean;
|
||||
onRegenerate?: () => Promise<void>;
|
||||
showRegenerate?: boolean;
|
||||
}
|
||||
|
||||
export function ApiKeyDisplay({
|
||||
@@ -18,7 +17,6 @@ export function ApiKeyDisplay({
|
||||
description,
|
||||
isSecret = false,
|
||||
onRegenerate,
|
||||
showRegenerate = false,
|
||||
}: ApiKeyDisplayProps) {
|
||||
const [showKey, setShowKey] = useState(!isSecret);
|
||||
const [copied, setCopied] = useState(false);
|
||||
@@ -101,7 +99,7 @@ export function ApiKeyDisplay({
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</Button>
|
||||
{showRegenerate && onRegenerate && (
|
||||
{onRegenerate && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
|
||||
@@ -59,13 +59,13 @@ const formatEmailCost = (emailCount: number, currency: string | null): string =>
|
||||
|
||||
interface BillingLimitsProps {
|
||||
projectId: string;
|
||||
hasSubscription: boolean;
|
||||
tier: 'free' | 'paid';
|
||||
billingEnabled: boolean;
|
||||
}
|
||||
|
||||
type LimitsFormValues = z.infer<typeof BillingLimitSchemas.update>;
|
||||
|
||||
export function BillingLimits({projectId, hasSubscription, billingEnabled}: BillingLimitsProps) {
|
||||
export function BillingLimits({projectId, tier, billingEnabled}: BillingLimitsProps) {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
@@ -132,7 +132,7 @@ export function BillingLimits({projectId, hasSubscription, billingEnabled}: Bill
|
||||
};
|
||||
|
||||
// Free tier projects can view their usage but can't edit limits
|
||||
const canEditLimits = hasSubscription;
|
||||
const canEditLimits = tier === 'paid';
|
||||
|
||||
// If billing is not enabled, don't show the component
|
||||
if (!billingEnabled) {
|
||||
@@ -160,7 +160,7 @@ export function BillingLimits({projectId, hasSubscription, billingEnabled}: Bill
|
||||
<CardHeader>
|
||||
<CardTitle>Billing Limits</CardTitle>
|
||||
<CardDescription>
|
||||
{hasSubscription
|
||||
{tier === 'paid'
|
||||
? 'Set monthly limits for each email category. Limits reset on the 1st of each month.'
|
||||
: 'Free tier projects have a total limit of 1,000 emails per month across all categories.'}
|
||||
</CardDescription>
|
||||
@@ -168,7 +168,7 @@ export function BillingLimits({projectId, hasSubscription, billingEnabled}: Bill
|
||||
<CardContent>
|
||||
<div className="space-y-6">
|
||||
{/* Free tier info banner */}
|
||||
{!hasSubscription && limitsData && (
|
||||
{tier !== 'paid' && limitsData && (
|
||||
<Alert>
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<div className="ml-2">
|
||||
@@ -208,7 +208,7 @@ export function BillingLimits({projectId, hasSubscription, billingEnabled}: Bill
|
||||
{!isEditing && limitsData && (
|
||||
<div className="space-y-4">
|
||||
{/* For free tier, show total usage across all categories */}
|
||||
{!hasSubscription ? (
|
||||
{tier !== 'paid' ? (
|
||||
<UsageDisplay
|
||||
category="Total Emails (All Categories)"
|
||||
usage={limitsData.workflows}
|
||||
|
||||
@@ -76,7 +76,6 @@ export function EmailEditor({value, onChange, placeholder, subject, from, replyT
|
||||
// Fetch contacts for preview using SWR
|
||||
const {contacts} = useContacts({limit: 50});
|
||||
|
||||
// Update available variables when fields change
|
||||
useEffect(() => {
|
||||
if (availableFields.length > 0) {
|
||||
setAvailableVariables(availableFields);
|
||||
|
||||
@@ -11,14 +11,9 @@ interface EmailSettingsProps {
|
||||
fromPlaceholder?: string;
|
||||
fromNamePlaceholder?: string;
|
||||
replyToPlaceholder?: string;
|
||||
showFromNameHelpText?: boolean;
|
||||
layout?: 'vertical' | 'grid';
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable email settings component for from, fromName, and replyTo fields
|
||||
* Used in campaign and template forms
|
||||
*/
|
||||
export function EmailSettings({
|
||||
from,
|
||||
fromName,
|
||||
@@ -29,7 +24,6 @@ export function EmailSettings({
|
||||
fromPlaceholder = 'hello',
|
||||
fromNamePlaceholder = 'Your Company',
|
||||
replyToPlaceholder,
|
||||
showFromNameHelpText = false,
|
||||
layout = 'grid',
|
||||
}: EmailSettingsProps) {
|
||||
// Use from email's local part as the reply-to placeholder if not provided
|
||||
@@ -63,11 +57,9 @@ export function EmailSettings({
|
||||
onChange={e => onFromNameChange(e.target.value)}
|
||||
placeholder={fromNamePlaceholder}
|
||||
/>
|
||||
{showFromNameHelpText && (
|
||||
<p className="text-xs text-neutral-500 mt-1">
|
||||
The sender name that appears in the recipient's inbox. Defaults to your project name if not set.
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-neutral-500 mt-1">
|
||||
The sender name that appears in the recipient's inbox. Defaults to your project name if not set.
|
||||
</p>
|
||||
</div>
|
||||
</GridWrapper>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user