mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-11-06 17:04:56 +05:30
Merge 166771d638 into 3b702b260c
This commit is contained in:
commit
03f73c58c4
8 changed files with 232 additions and 1 deletions
|
|
@ -50,9 +50,9 @@ export default function ToolTextInput({
|
|||
value={value}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
fullWidth
|
||||
placeholder={placeholder}
|
||||
multiline
|
||||
rows={10}
|
||||
placeholder={placeholder}
|
||||
sx={{
|
||||
'&.MuiTextField-root': {
|
||||
backgroundColor: 'background.paper'
|
||||
|
|
|
|||
60
src/components/result/ValidatedToolResult.tsx
Normal file
60
src/components/result/ValidatedToolResult.tsx
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import React from 'react';
|
||||
import { Alert } from '@mui/material';
|
||||
|
||||
interface ValidatedToolResultProps {
|
||||
isValid: boolean | null;
|
||||
hasInteracted: boolean;
|
||||
errorMessage?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ValidatedToolResult: React.FC<ValidatedToolResultProps> = ({
|
||||
isValid,
|
||||
hasInteracted,
|
||||
errorMessage = 'Invalid input.',
|
||||
children
|
||||
}) => (
|
||||
<div style={{ position: 'relative', minHeight: 80 }}>
|
||||
{hasInteracted && isValid === false && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
zIndex: 2,
|
||||
pointerEvents: 'auto',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: 'transparent'
|
||||
}}
|
||||
>
|
||||
<Alert
|
||||
severity="error"
|
||||
style={{
|
||||
width: '80%',
|
||||
opacity: 0.85,
|
||||
textAlign: 'center',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
>
|
||||
{errorMessage}
|
||||
</Alert>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
filter: hasInteracted && isValid === false ? 'blur(1px)' : 'none',
|
||||
transition: 'filter 0.2s'
|
||||
}}
|
||||
>
|
||||
{hasInteracted && isValid === false
|
||||
? React.cloneElement(children as React.ReactElement, { value: '' })
|
||||
: children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ValidatedToolResult;
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { expect, describe, it } from 'vitest';
|
||||
import { epochToDate, dateToEpoch, main } from './service';
|
||||
|
||||
describe('epoch-converter service', () => {
|
||||
it('converts epoch (seconds) to date', () => {
|
||||
expect(epochToDate('1609459200')).toBe('Fri, 01 Jan 2021 00:00:00 GMT');
|
||||
});
|
||||
it('converts epoch (milliseconds) to date', () => {
|
||||
expect(epochToDate('1609459200000')).toBe('Fri, 01 Jan 2021 00:00:00 GMT');
|
||||
});
|
||||
it('returns error for invalid epoch', () => {
|
||||
expect(epochToDate('notanumber')).toMatch(/Invalid epoch/);
|
||||
});
|
||||
it('converts date string to epoch', () => {
|
||||
expect(dateToEpoch('2021-01-01T00:00:00Z')).toBe('1609459200');
|
||||
});
|
||||
it('returns error for invalid date string', () => {
|
||||
expect(dateToEpoch('notadate')).toMatch(/Invalid date/);
|
||||
});
|
||||
it('main: detects and converts epoch', () => {
|
||||
expect(main('1609459200', {})).toBe('Fri, 01 Jan 2021 00:00:00 GMT');
|
||||
});
|
||||
it('main: detects and converts date', () => {
|
||||
expect(main('2021-01-01T00:00:00Z', {})).toBe('1609459200');
|
||||
});
|
||||
it('main: returns error for invalid input', () => {
|
||||
expect(main('notadate', {})).toMatch(/Invalid date/);
|
||||
expect(main('notanumber', {})).toMatch(/Invalid date/);
|
||||
});
|
||||
});
|
||||
87
src/pages/tools/time/epoch-converter/index.tsx
Normal file
87
src/pages/tools/time/epoch-converter/index.tsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import { Alert, Button, Stack } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import ToolContent from '@components/ToolContent';
|
||||
import { ToolComponentProps } from '@tools/defineTool';
|
||||
import ToolTextInput from '@components/input/ToolTextInput';
|
||||
import ToolTextResult from '@components/result/ToolTextResult';
|
||||
import { CardExampleType } from '@components/examples/ToolExamples';
|
||||
import { main } from './service';
|
||||
import { InitialValuesType } from './types';
|
||||
import ValidatedToolResult from '@components/result/ValidatedToolResult';
|
||||
|
||||
const initialValues: InitialValuesType = {};
|
||||
|
||||
const exampleCards: CardExampleType<InitialValuesType>[] = [
|
||||
{
|
||||
title: 'Epoch to Date (seconds)',
|
||||
description: 'Convert Unix timestamp (seconds) to date',
|
||||
sampleText: '1609459200',
|
||||
sampleResult: 'Fri, 01 Jan 2021 00:00:00 GMT',
|
||||
sampleOptions: {}
|
||||
},
|
||||
{
|
||||
title: 'Epoch to Date (milliseconds)',
|
||||
description: 'Convert Unix timestamp (milliseconds) to date',
|
||||
sampleText: '1609459200000',
|
||||
sampleResult: 'Fri, 01 Jan 2021 00:00:00 GMT',
|
||||
sampleOptions: {}
|
||||
},
|
||||
{
|
||||
title: 'Date to Epoch',
|
||||
description: 'Convert date string to Unix timestamp (seconds)',
|
||||
sampleText: '2021-01-01T00:00:00Z',
|
||||
sampleResult: '1609459200',
|
||||
sampleOptions: {}
|
||||
}
|
||||
];
|
||||
|
||||
export default function EpochConverter({
|
||||
title,
|
||||
longDescription
|
||||
}: ToolComponentProps) {
|
||||
const [input, setInput] = useState<string>('');
|
||||
const [result, setResult] = useState<string>('');
|
||||
const [hasInteracted, setHasInteracted] = useState<boolean>(false);
|
||||
const [isValid, setIsValid] = useState<boolean | null>(null);
|
||||
|
||||
const compute = (_values: InitialValuesType, input: string) => {
|
||||
const output = main(input, {});
|
||||
const invalid = output.startsWith('Invalid');
|
||||
setIsValid(!invalid);
|
||||
setResult(output);
|
||||
};
|
||||
|
||||
const handleInputChange = (val: string) => {
|
||||
if (!hasInteracted) setHasInteracted(true);
|
||||
setInput(val);
|
||||
};
|
||||
|
||||
return (
|
||||
<ToolContent
|
||||
title={title}
|
||||
input={input}
|
||||
inputComponent={
|
||||
<ToolTextInput
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Enter epoch timestamp or date string (e.g. 1609459200 or 2021-01-01T00:00:00Z)"
|
||||
/>
|
||||
}
|
||||
resultComponent={
|
||||
<ValidatedToolResult
|
||||
isValid={isValid}
|
||||
hasInteracted={hasInteracted}
|
||||
errorMessage="Invalid input. Please enter a valid epoch timestamp or date string."
|
||||
>
|
||||
<ToolTextResult value={result} />
|
||||
</ValidatedToolResult>
|
||||
}
|
||||
initialValues={initialValues}
|
||||
exampleCards={exampleCards}
|
||||
getGroups={null}
|
||||
setInput={setInput}
|
||||
compute={compute}
|
||||
toolInfo={{ title: `What is a ${title}?`, description: longDescription }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
23
src/pages/tools/time/epoch-converter/meta.ts
Normal file
23
src/pages/tools/time/epoch-converter/meta.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { defineTool } from '@tools/defineTool';
|
||||
import { lazy } from 'react';
|
||||
|
||||
export const tool = defineTool('time', {
|
||||
name: 'Epoch Converter',
|
||||
path: 'epoch-converter',
|
||||
icon: 'mdi:clock-time-four-outline',
|
||||
description:
|
||||
'Convert Unix epoch timestamps to human-readable dates and vice versa.',
|
||||
shortDescription: 'Convert between Unix timestamps and dates.',
|
||||
keywords: [
|
||||
'epoch',
|
||||
'converter',
|
||||
'timestamp',
|
||||
'date',
|
||||
'unix',
|
||||
'time',
|
||||
'convert'
|
||||
],
|
||||
longDescription:
|
||||
'Enter a Unix timestamp (in seconds or milliseconds) to get a human-readable date, or enter a date string (e.g., 2021-01-01T00:00:00Z) to get the corresponding Unix timestamp. Useful for developers, sysadmins, and anyone working with time data.',
|
||||
component: lazy(() => import('./index'))
|
||||
});
|
||||
26
src/pages/tools/time/epoch-converter/service.ts
Normal file
26
src/pages/tools/time/epoch-converter/service.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { InitialValuesType } from './types';
|
||||
|
||||
export function epochToDate(input: string): string {
|
||||
const num = Number(input);
|
||||
if (isNaN(num)) return 'Invalid epoch timestamp.';
|
||||
// Support both seconds and milliseconds
|
||||
const date = new Date(num > 1e12 ? num : num * 1000);
|
||||
if (isNaN(date.getTime())) return 'Invalid epoch timestamp.';
|
||||
return date.toUTCString();
|
||||
}
|
||||
|
||||
export function dateToEpoch(input: string): string {
|
||||
const date = new Date(input);
|
||||
if (isNaN(date.getTime())) return 'Invalid date string.';
|
||||
return Math.floor(date.getTime() / 1000).toString();
|
||||
}
|
||||
|
||||
export function main(input: string, _options: any): string {
|
||||
if (!input.trim()) return '';
|
||||
// If input is a number, treat as epoch
|
||||
if (/^-?\d+(\.\d+)?$/.test(input.trim())) {
|
||||
return epochToDate(input.trim());
|
||||
}
|
||||
// Otherwise, treat as date string
|
||||
return dateToEpoch(input.trim());
|
||||
}
|
||||
3
src/pages/tools/time/epoch-converter/types.ts
Normal file
3
src/pages/tools/time/epoch-converter/types.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export type InitialValuesType = {
|
||||
// splitSeparator: string;
|
||||
};
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { tool as timeEpochConverter } from './epoch-converter/meta';
|
||||
import { tool as timeCrontabGuru } from './crontab-guru/meta';
|
||||
import { tool as timeBetweenDates } from './time-between-dates/meta';
|
||||
import { tool as daysDoHours } from './convert-days-to-hours/meta';
|
||||
|
|
@ -14,6 +15,7 @@ export const timeTools = [
|
|||
convertTimetoSeconds,
|
||||
truncateClockTime,
|
||||
timeBetweenDates,
|
||||
timeEpochConverter,
|
||||
timeCrontabGuru,
|
||||
checkLeapYear
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue