mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-01-14 20:11:17 +01:00
added aplha tag, made it require premium and changed the icon
This commit is contained in:
parent
4bd01eb47b
commit
3a7ec0ff38
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Text } from '@mantine/core';
|
||||
import { Text, Badge } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Tooltip } from '@app/components/shared/Tooltip';
|
||||
import HotkeyDisplay from '@app/components/hotkeys/HotkeyDisplay';
|
||||
@ -17,10 +17,14 @@ interface CompactToolItemProps {
|
||||
|
||||
const CompactToolItem: React.FC<CompactToolItemProps> = ({ id, tool, isSelected, onClick, tooltipPortalTarget }) => {
|
||||
const { t } = useTranslation();
|
||||
const { binding, isFav, toggleFavorite, disabled } = useToolMeta(id, tool);
|
||||
const { binding, isFav, toggleFavorite, disabled, premiumEnabled } = useToolMeta(id, tool);
|
||||
const categoryColor = getSubcategoryColor(tool.subcategoryId);
|
||||
const iconBg = getIconBackground(categoryColor, false);
|
||||
const iconClasses = 'tool-panel__fullscreen-list-icon';
|
||||
|
||||
// Determine why tool is disabled for tooltip content
|
||||
const isUnavailable = !tool.component && !tool.link && id !== 'read' && id !== 'multiTool';
|
||||
const requiresPremiumButNotEnabled = tool.requiresPremium === true && premiumEnabled !== true;
|
||||
|
||||
let iconNode: React.ReactNode = null;
|
||||
if (React.isValidElement<{ style?: React.CSSProperties }>(tool.icon)) {
|
||||
@ -57,9 +61,20 @@ const CompactToolItem: React.FC<CompactToolItemProps> = ({ id, tool, isSelected,
|
||||
</span>
|
||||
) : null}
|
||||
<span className="tool-panel__fullscreen-list-body">
|
||||
<Text fw={600} size="sm" className="tool-panel__fullscreen-name">
|
||||
{tool.name}
|
||||
</Text>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
||||
<Text fw={600} size="sm" className="tool-panel__fullscreen-name">
|
||||
{tool.name}
|
||||
</Text>
|
||||
{tool.versionStatus === 'alpha' && (
|
||||
<Badge
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="orange"
|
||||
>
|
||||
{t('toolPanel.alpha', 'Alpha')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
{!disabled && (
|
||||
<div className="tool-panel__fullscreen-star-compact">
|
||||
@ -73,11 +88,22 @@ const CompactToolItem: React.FC<CompactToolItemProps> = ({ id, tool, isSelected,
|
||||
</button>
|
||||
);
|
||||
|
||||
const tooltipContent = disabled
|
||||
? (
|
||||
<span><strong>{t('toolPanel.fullscreen.comingSoon', 'Coming soon:')}</strong> {tool.description}</span>
|
||||
)
|
||||
: (
|
||||
// Determine tooltip content based on disabled reason
|
||||
let tooltipContent: React.ReactNode;
|
||||
if (requiresPremiumButNotEnabled) {
|
||||
tooltipContent = (
|
||||
<span>
|
||||
<strong>{t('toolPanel.premiumFeature', 'Premium feature:')}</strong> {tool.description}
|
||||
</span>
|
||||
);
|
||||
} else if (isUnavailable) {
|
||||
tooltipContent = (
|
||||
<span>
|
||||
<strong>{t('toolPanel.fullscreen.comingSoon', 'Coming soon:')}</strong> {tool.description}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
tooltipContent = (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem' }}>
|
||||
<span>{tool.description}</span>
|
||||
{binding && (
|
||||
@ -90,6 +116,7 @@ const CompactToolItem: React.FC<CompactToolItemProps> = ({ id, tool, isSelected,
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Text } from '@mantine/core';
|
||||
import { Text, Badge } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import HotkeyDisplay from '@app/components/hotkeys/HotkeyDisplay';
|
||||
import FavoriteStar from '@app/components/tools/toolPicker/FavoriteStar';
|
||||
@ -56,9 +56,21 @@ const DetailedToolItem: React.FC<DetailedToolItemProps> = ({ id, tool, isSelecte
|
||||
</span>
|
||||
) : null}
|
||||
<span className="tool-panel__fullscreen-body">
|
||||
<Text fw={600} size="sm" className="tool-panel__fullscreen-name">
|
||||
{tool.name}
|
||||
</Text>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
||||
<Text fw={600} size="sm" className="tool-panel__fullscreen-name">
|
||||
{tool.name}
|
||||
</Text>
|
||||
{tool.versionStatus === 'alpha' && (
|
||||
<Badge
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="orange"
|
||||
>
|
||||
{/* we can add more translations for different badges in future, like beta, etc. */}
|
||||
{t('toolPanel.alpha', 'Alpha')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<Text size="sm" c="dimmed" className="tool-panel__fullscreen-description">
|
||||
{tool.description}
|
||||
</Text>
|
||||
|
||||
@ -2,6 +2,7 @@ import { useHotkeys } from '@app/contexts/HotkeyContext';
|
||||
import { useToolWorkflow } from '@app/contexts/ToolWorkflowContext';
|
||||
import { ToolRegistryEntry } from '@app/data/toolsTaxonomy';
|
||||
import { ToolId } from '@app/types/toolId';
|
||||
import { useAppConfig } from '@app/contexts/AppConfigContext';
|
||||
|
||||
export const getItemClasses = (isDetailed: boolean): string => {
|
||||
return isDetailed ? 'tool-panel__fullscreen-item--detailed' : '';
|
||||
@ -22,23 +23,32 @@ export const getIconStyle = (): Record<string, string> => {
|
||||
return {};
|
||||
};
|
||||
|
||||
export const isToolDisabled = (id: string, tool: ToolRegistryEntry): boolean => {
|
||||
return !tool.component && !tool.link && id !== 'read' && id !== 'multiTool';
|
||||
export const isToolDisabled = (id: string, tool: ToolRegistryEntry, premiumEnabled?: boolean): boolean => {
|
||||
// Check if tool is unavailable (no component and not a link)
|
||||
const isUnavailable = !tool.component && !tool.link && id !== 'read' && id !== 'multiTool';
|
||||
|
||||
// Check if tool requires premium but premium is not enabled
|
||||
const requiresPremiumButNotEnabled = tool.requiresPremium === true && premiumEnabled !== true;
|
||||
|
||||
return isUnavailable || requiresPremiumButNotEnabled;
|
||||
};
|
||||
|
||||
export function useToolMeta(id: string, tool: ToolRegistryEntry) {
|
||||
const { hotkeys } = useHotkeys();
|
||||
const { isFavorite, toggleFavorite } = useToolWorkflow();
|
||||
const { config } = useAppConfig();
|
||||
const premiumEnabled = config?.premiumEnabled;
|
||||
|
||||
const isFav = isFavorite(id as ToolId);
|
||||
const binding = hotkeys[id as ToolId];
|
||||
const disabled = isToolDisabled(id, tool);
|
||||
const disabled = isToolDisabled(id, tool, premiumEnabled);
|
||||
|
||||
return {
|
||||
binding,
|
||||
isFav,
|
||||
toggleFavorite: () => toggleFavorite(id as ToolId),
|
||||
disabled,
|
||||
premiumEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { Button } from "@mantine/core";
|
||||
import { Button, Badge } from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Tooltip } from "@app/components/shared/Tooltip";
|
||||
import { ToolIcon } from "@app/components/shared/ToolIcon";
|
||||
@ -12,6 +12,7 @@ import HotkeyDisplay from "@app/components/hotkeys/HotkeyDisplay";
|
||||
import FavoriteStar from "@app/components/tools/toolPicker/FavoriteStar";
|
||||
import { useToolWorkflow } from "@app/contexts/ToolWorkflowContext";
|
||||
import { ToolId } from "@app/types/toolId";
|
||||
import { useAppConfig } from "@app/contexts/AppConfigContext";
|
||||
|
||||
interface ToolButtonProps {
|
||||
id: ToolId;
|
||||
@ -26,8 +27,15 @@ interface ToolButtonProps {
|
||||
|
||||
const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect, disableNavigation = false, matchedSynonym, hasStars = false }) => {
|
||||
const { t } = useTranslation();
|
||||
// Special case: read and multiTool are navigational tools that are always available
|
||||
const { config } = useAppConfig();
|
||||
const premiumEnabled = config?.premiumEnabled;
|
||||
|
||||
// Check if disabled due to premium requirement
|
||||
const requiresPremiumButNotEnabled = tool.requiresPremium === true && premiumEnabled !== true;
|
||||
// Check if tool is unavailable (no component, no link, except read/multiTool)
|
||||
const isUnavailable = !tool.component && !tool.link && id !== 'read' && id !== 'multiTool';
|
||||
const isDisabled = isUnavailable || requiresPremiumButNotEnabled;
|
||||
|
||||
const { hotkeys } = useHotkeys();
|
||||
const binding = hotkeys[id];
|
||||
const { getToolNavigation } = useToolNavigation();
|
||||
@ -35,7 +43,7 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
const fav = isFavorite(id as ToolId);
|
||||
|
||||
const handleClick = (id: ToolId) => {
|
||||
if (isUnavailable) return;
|
||||
if (isDisabled) return;
|
||||
if (tool.link) {
|
||||
// Open external link in new tab
|
||||
window.open(tool.link, '_blank', 'noopener,noreferrer');
|
||||
@ -46,11 +54,24 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
};
|
||||
|
||||
// Get navigation props for URL support (only if navigation is not disabled)
|
||||
const navProps = !isUnavailable && !tool.link && !disableNavigation ? getToolNavigation(id, tool) : null;
|
||||
const navProps = !isDisabled && !tool.link && !disableNavigation ? getToolNavigation(id, tool) : null;
|
||||
|
||||
const tooltipContent = isUnavailable
|
||||
? (<span><strong>Coming soon:</strong> {tool.description}</span>)
|
||||
: (
|
||||
// Determine tooltip content based on disabled reason
|
||||
let tooltipContent: React.ReactNode;
|
||||
if (requiresPremiumButNotEnabled) {
|
||||
tooltipContent = (
|
||||
<span>
|
||||
<strong>{t('toolPanel.premiumFeature', 'Premium feature:')}</strong> {tool.description}
|
||||
</span>
|
||||
);
|
||||
} else if (isDisabled) {
|
||||
tooltipContent = (
|
||||
<span>
|
||||
<strong>{t('toolPanel.comingSoon', 'Coming soon:')}</strong> {tool.description}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
tooltipContent = (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem' }}>
|
||||
<span>{tool.description}</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', fontSize: '0.75rem' }}>
|
||||
@ -65,26 +86,39 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const buttonContent = (
|
||||
<>
|
||||
<ToolIcon
|
||||
icon={tool.icon}
|
||||
opacity={isUnavailable ? 0.25 : 1}
|
||||
opacity={isDisabled ? 0.25 : 1}
|
||||
/>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', flex: 1, overflow: 'visible' }}>
|
||||
<FitText
|
||||
text={tool.name}
|
||||
lines={1}
|
||||
minimumFontScale={0.8}
|
||||
as="span"
|
||||
style={{ display: 'inline-block', maxWidth: '100%', opacity: isUnavailable ? 0.25 : 1 }}
|
||||
/>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', width: '100%' }}>
|
||||
<FitText
|
||||
text={tool.name}
|
||||
lines={1}
|
||||
minimumFontScale={0.8}
|
||||
as="span"
|
||||
style={{ display: 'inline-block', maxWidth: '100%', opacity: isDisabled ? 0.25 : 1 }}
|
||||
/>
|
||||
{tool.versionStatus === 'alpha' && (
|
||||
<Badge
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="orange"
|
||||
style={{ flexShrink: 0, opacity: isDisabled ? 0.25 : 1 }}
|
||||
>
|
||||
{t('toolPanel.alpha', 'Alpha')}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{matchedSynonym && (
|
||||
<span style={{
|
||||
fontSize: '0.75rem',
|
||||
color: 'var(--mantine-color-dimmed)',
|
||||
opacity: isUnavailable ? 0.25 : 1,
|
||||
opacity: isDisabled ? 0.25 : 1,
|
||||
marginTop: '1px',
|
||||
overflow: 'visible',
|
||||
whiteSpace: 'nowrap'
|
||||
@ -124,7 +158,7 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
>
|
||||
{buttonContent}
|
||||
</Button>
|
||||
) : tool.link && !isUnavailable ? (
|
||||
) : tool.link && !isDisabled ? (
|
||||
// For external links, render Button as an anchor with proper href
|
||||
<Button
|
||||
component="a"
|
||||
@ -151,7 +185,7 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
{buttonContent}
|
||||
</Button>
|
||||
) : (
|
||||
// For unavailable tools, use regular button
|
||||
// For unavailable/premium tools, use regular button
|
||||
<Button
|
||||
variant={isSelected ? "filled" : "subtle"}
|
||||
onClick={() => handleClick(id)}
|
||||
@ -160,13 +194,13 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
fullWidth
|
||||
justify="flex-start"
|
||||
className="tool-button"
|
||||
aria-disabled={isUnavailable}
|
||||
aria-disabled={isDisabled}
|
||||
data-tour={`tool-button-${id}`}
|
||||
styles={{
|
||||
root: {
|
||||
borderRadius: 0,
|
||||
color: "var(--tools-text-and-icon-color)",
|
||||
cursor: isUnavailable ? 'not-allowed' : undefined,
|
||||
cursor: isDisabled ? 'not-allowed' : undefined,
|
||||
overflow: 'visible'
|
||||
},
|
||||
label: { overflow: 'visible' }
|
||||
@ -176,7 +210,7 @@ const ToolButton: React.FC<ToolButtonProps> = ({ id, tool, isSelected, onSelect,
|
||||
</Button>
|
||||
);
|
||||
|
||||
const star = hasStars && !isUnavailable ? (
|
||||
const star = hasStars && !isDisabled ? (
|
||||
<FavoriteStar
|
||||
isFavorite={fav}
|
||||
onToggle={() => toggleFavorite(id as ToolId)}
|
||||
|
||||
@ -21,6 +21,7 @@ import {
|
||||
import type { ToolPanelMode } from '@app/constants/toolPanel';
|
||||
import { usePreferences } from '@app/contexts/PreferencesContext';
|
||||
import { useToolRegistry } from '@app/contexts/ToolRegistryContext';
|
||||
import { useAppConfig } from '@app/contexts/AppConfigContext';
|
||||
|
||||
// State interface
|
||||
// Types and reducer/state moved to './toolWorkflow/state'
|
||||
@ -114,6 +115,8 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
||||
// Tool management hook
|
||||
const { toolRegistry, getSelectedTool } = useToolManagement();
|
||||
const { allTools } = useToolRegistry();
|
||||
const { config } = useAppConfig();
|
||||
const premiumEnabled = config?.premiumEnabled;
|
||||
|
||||
// Tool history hook
|
||||
const {
|
||||
@ -268,6 +271,13 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
||||
|
||||
// Workflow actions (compound actions that coordinate multiple state changes)
|
||||
const handleToolSelect = useCallback((toolId: ToolId) => {
|
||||
// Check if tool requires premium and premium is not enabled
|
||||
const selectedTool = allTools[toolId];
|
||||
if (selectedTool?.requiresPremium === true && premiumEnabled !== true) {
|
||||
// Premium tool selected without premium - do nothing (should be disabled in UI)
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're currently on a custom workbench (e.g., Validate Signature report),
|
||||
// selecting any tool should take the user back to the default file manager view.
|
||||
const wasInCustomWorkbench = !isBaseWorkbench(navigationState.workbench);
|
||||
@ -309,7 +319,7 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
||||
setSearchQuery('');
|
||||
setLeftPanelView('toolContent');
|
||||
setReaderMode(false); // Disable read mode when selecting tools
|
||||
}, [actions, getSelectedTool, navigationState.workbench, setLeftPanelView, setReaderMode, setSearchQuery]);
|
||||
}, [actions, getSelectedTool, navigationState.workbench, setLeftPanelView, setReaderMode, setSearchQuery, allTools, premiumEnabled]);
|
||||
|
||||
const handleBackToTools = useCallback(() => {
|
||||
setLeftPanelView('toolPicker');
|
||||
|
||||
@ -59,6 +59,10 @@ export type ToolRegistryEntry = {
|
||||
supportsAutomate?: boolean;
|
||||
// Synonyms for search (optional)
|
||||
synonyms?: string[];
|
||||
// Version status indicator (e.g., "alpha", "beta")
|
||||
versionStatus?: "alpha" | "beta";
|
||||
// Whether this tool requires premium access
|
||||
requiresPremium?: boolean;
|
||||
}
|
||||
|
||||
export type RegularToolRegistry = Record<RegularToolId, ToolRegistryEntry>;
|
||||
|
||||
@ -4,6 +4,7 @@ import { getAllEndpoints, type ToolRegistryEntry, type ToolRegistry } from "@app
|
||||
import { useMultipleEndpointsEnabled } from "@app/hooks/useEndpointConfig";
|
||||
import { FileId } from '@app/types/file';
|
||||
import { ToolId } from "@app/types/toolId";
|
||||
import { useAppConfig } from "@app/contexts/AppConfigContext";
|
||||
|
||||
interface ToolManagementResult {
|
||||
selectedTool: ToolRegistryEntry | null;
|
||||
@ -15,6 +16,7 @@ interface ToolManagementResult {
|
||||
|
||||
export const useToolManagement = (): ToolManagementResult => {
|
||||
const [toolSelectedFileIds, setToolSelectedFileIds] = useState<FileId[]>([]);
|
||||
const { config } = useAppConfig();
|
||||
|
||||
// Build endpoints list from registry entries with fallback to legacy mapping
|
||||
const { allTools } = useToolRegistry();
|
||||
@ -39,11 +41,18 @@ export const useToolManagement = (): ToolManagementResult => {
|
||||
}, [endpointsLoading, endpointStatus, baseRegistry]);
|
||||
|
||||
const toolRegistry: Partial<ToolRegistry> = useMemo(() => {
|
||||
// Include tools that either:
|
||||
// 1. Have enabled endpoints (normal filtering), OR
|
||||
// 2. Are premium tools (so they show up even if premium is not enabled, but will be disabled)
|
||||
const availableToolRegistry: Partial<ToolRegistry> = {};
|
||||
(Object.keys(baseRegistry) as ToolId[]).forEach(toolKey => {
|
||||
if (isToolAvailable(toolKey)) {
|
||||
const baseTool = baseRegistry[toolKey];
|
||||
if (baseTool) {
|
||||
const baseTool = baseRegistry[toolKey];
|
||||
if (baseTool) {
|
||||
const hasEnabledEndpoints = isToolAvailable(toolKey);
|
||||
const isPremiumTool = baseTool.requiresPremium === true;
|
||||
|
||||
// Include if endpoints are enabled OR if it's a premium tool (to show it disabled)
|
||||
if (hasEnabledEndpoints || isPremiumTool) {
|
||||
availableToolRegistry[toolKey] = {
|
||||
...baseTool,
|
||||
name: baseTool.name,
|
||||
|
||||
@ -8,6 +8,7 @@ import { parseToolRoute, updateToolRoute, clearToolRoute } from '@app/utils/urlR
|
||||
import { ToolRegistry } from '@app/data/toolsTaxonomy';
|
||||
import { firePixel } from '@app/utils/scarfTracking';
|
||||
import { withBasePath } from '@app/constants/app';
|
||||
import { useAppConfig } from '@app/contexts/AppConfigContext';
|
||||
|
||||
/**
|
||||
* Hook to sync workbench and tool with URL using registry
|
||||
@ -19,11 +20,33 @@ export function useNavigationUrlSync(
|
||||
registry: ToolRegistry,
|
||||
enableSync: boolean = true
|
||||
) {
|
||||
const { config } = useAppConfig();
|
||||
const premiumEnabled = config?.premiumEnabled;
|
||||
const hasInitialized = useRef(false);
|
||||
const prevSelectedTool = useRef<ToolId | null>(null);
|
||||
|
||||
// Check if tool requires premium and redirect if needed
|
||||
const checkPremiumAndSelect = useCallback((toolId: ToolId) => {
|
||||
const tool = registry[toolId];
|
||||
if (tool?.requiresPremium === true && premiumEnabled !== true) {
|
||||
// Premium tool accessed without premium - redirect to home
|
||||
const homePath = withBasePath('/');
|
||||
if (window.location.pathname !== homePath) {
|
||||
clearToolRoute(true); // Use replaceState to avoid adding to history
|
||||
window.location.href = homePath;
|
||||
}
|
||||
return;
|
||||
}
|
||||
handleToolSelect(toolId);
|
||||
}, [registry, premiumEnabled, handleToolSelect]);
|
||||
|
||||
// Initialize workbench and tool from URL on mount
|
||||
useEffect(() => {
|
||||
if (!enableSync) return;
|
||||
// Wait for config to load before checking premium status
|
||||
if (config === null) return;
|
||||
// Only run once on initial mount
|
||||
if (hasInitialized.current) return;
|
||||
|
||||
// Fire pixel for initial page load
|
||||
const currentPath = window.location.pathname;
|
||||
@ -32,7 +55,7 @@ export function useNavigationUrlSync(
|
||||
const route = parseToolRoute(registry);
|
||||
if (route.toolId !== selectedTool) {
|
||||
if (route.toolId) {
|
||||
handleToolSelect(route.toolId);
|
||||
checkPremiumAndSelect(route.toolId);
|
||||
} else if (selectedTool !== null) {
|
||||
// Only clear selection if we actually had a tool selected
|
||||
// Don't clear on initial load when selectedTool starts as null
|
||||
@ -41,7 +64,7 @@ export function useNavigationUrlSync(
|
||||
}
|
||||
|
||||
hasInitialized.current = true;
|
||||
}, []); // Only run on mount
|
||||
}, [checkPremiumAndSelect, config, enableSync, registry, selectedTool]); // Include dependencies
|
||||
|
||||
// Update URL when tool or workbench changes
|
||||
useEffect(() => {
|
||||
@ -73,7 +96,7 @@ export function useNavigationUrlSync(
|
||||
firePixel(currentPath);
|
||||
|
||||
if (route.toolId) {
|
||||
handleToolSelect(route.toolId);
|
||||
checkPremiumAndSelect(route.toolId);
|
||||
} else {
|
||||
clearToolSelection();
|
||||
}
|
||||
@ -82,7 +105,7 @@ export function useNavigationUrlSync(
|
||||
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
return () => window.removeEventListener('popstate', handlePopState);
|
||||
}, [selectedTool, handleToolSelect, clearToolSelection, registry, enableSync]);
|
||||
}, [selectedTool, handleToolSelect, clearToolSelection, registry, enableSync, checkPremiumAndSelect]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -126,4 +126,7 @@ export const URL_TO_TOOL_MAP: Record<string, ToolId> = {
|
||||
'/overlay-pdf': 'overlayPdfs',
|
||||
'/split-pdf-by-sections': 'split',
|
||||
'/split-pdf-by-chapters': 'split',
|
||||
|
||||
// Premium tools
|
||||
'/pdf-text-editor': 'pdfTextEditor',
|
||||
};
|
||||
|
||||
@ -20,7 +20,7 @@ export function useProprietaryToolRegistry(): ProprietaryToolRegistry {
|
||||
|
||||
return useMemo<ProprietaryToolRegistry>(() => ({
|
||||
pdfTextEditor: {
|
||||
icon: <LocalIcon icon="code-rounded" width="1.5rem" height="1.5rem" />,
|
||||
icon: <LocalIcon icon="edit-square-outline-rounded" width="1.5rem" height="1.5rem" />,
|
||||
name: t("home.pdfTextEditor.title", "PDF Text Editor"),
|
||||
component: PdfTextEditor,
|
||||
description: t(
|
||||
@ -34,6 +34,8 @@ export function useProprietaryToolRegistry(): ProprietaryToolRegistry {
|
||||
synonyms: getSynonyms(t, "pdfTextEditor"),
|
||||
supportsAutomate: false,
|
||||
automationSettings: null,
|
||||
versionStatus: "alpha",
|
||||
requiresPremium: true,
|
||||
},
|
||||
}), [t]);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user