-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
188ce61
commit 6bc6494
Showing
7 changed files
with
202 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,19 @@ | ||
import { useState } from 'react'; | ||
import { Copy, Link, AlertCircle } from 'lucide-react'; | ||
import { useEffect } from 'react'; | ||
import Home from './components/Home'; | ||
import View from './components/View'; | ||
import { isValidUUID } from './lib/utils'; | ||
|
||
const OneTimeSecret = () => { | ||
const [secret, setSecret] = useState(''); | ||
const [generatedLink, setGeneratedLink] = useState(''); | ||
const [inputEnabled, setInputEnabled] = useState(true); | ||
const [error, setError] = useState(''); | ||
|
||
const handleCreateLink = () => { | ||
const data = secret.trim(); | ||
if (!data.trim()) { | ||
setError('Please enter a secret to create a link.'); | ||
return; | ||
} | ||
|
||
setInputEnabled(false); | ||
|
||
const fetchData = async () => { | ||
const response = await fetch('/api/secret/new', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ data: data.trim() }), | ||
}); | ||
|
||
if (response.ok) { | ||
const data = await response.json(); | ||
setGeneratedLink(`${window.location.origin}/${data.id}`); | ||
} else { | ||
setGeneratedLink(''); | ||
setError('An error occurred while creating the secret link. Please refresh and try again.'); | ||
} | ||
}; | ||
|
||
fetchData(); | ||
const App = () => { | ||
const hash = window.location.hash.substring(1); | ||
if (!isValidUUID(hash) && window.location.pathname !== '/') { | ||
window.location.replace('/'); | ||
} | ||
|
||
const handleCopyLink = () => { | ||
navigator.clipboard.writeText(generatedLink); | ||
}; | ||
|
||
return ( | ||
<div className="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800 flex items-center justify-center p-4"> | ||
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-md border border-gray-700"> | ||
<h1 className="text-2xl font-bold text-gray-100 mb-4 text-center">Create One-Time Secret</h1> | ||
<textarea | ||
className="w-full h-32 p-2 border border-gray-600 rounded-md focus:ring-2 focus:ring-purple-500 focus:border-transparent resize-none bg-gray-700 text-gray-100 disabled:opacity-50 disabled:cursor-not-allowed" | ||
placeholder="Enter your secret here..." | ||
value={secret} | ||
onChange={(e) => setSecret(e.target.value)} | ||
disabled={!inputEnabled} | ||
maxLength={10000} | ||
/> | ||
<button | ||
className={`mt-4 w-full bg-purple-600 text-white font-bold py-2 px-4 rounded-md transition duration-300 ease-in-out flex items-center justify-center ${!generatedLink | ||
? 'hover:bg-purple-700 hover:shadow-lg transform hover:-translate-y-0.5' | ||
: 'opacity-50 cursor-not-allowed' | ||
}`} | ||
onClick={handleCreateLink} | ||
disabled={!inputEnabled} | ||
> | ||
<Link className="mr-2" size={18} /> | ||
Create Secret Link | ||
</button> | ||
|
||
{generatedLink && ( | ||
<div className="mt-4"> | ||
<p className="text-sm text-gray-400 mb-2">Your secret link:</p> | ||
<div className="flex items-center bg-gray-700 p-2 rounded-md"> | ||
<input | ||
type="text" | ||
readOnly | ||
value={generatedLink} | ||
className="flex-grow bg-transparent text-sm text-gray-300 focus:outline-none" | ||
/> | ||
<button | ||
onClick={handleCopyLink} | ||
className="ml-2 text-purple-400 hover:text-purple-300 transition duration-300 ease-in-out transform hover:scale-110" | ||
title="Copy to clipboard" | ||
> | ||
<Copy size={18} /> | ||
</button> | ||
</div> | ||
</div> | ||
)} | ||
|
||
{error && ( | ||
<div className="mt-4 bg-red-900 border border-red-700 text-red-100 px-4 py-3 rounded relative" role="alert"> | ||
<div className="flex items-center"> | ||
<AlertCircle className="mr-2" size={18} /> | ||
<span className="block sm:inline pl-2 pr-2">{error}</span> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
<> | ||
{isValidUUID(hash) ? <View hash={hash} /> : <Home />} | ||
</> | ||
); | ||
}; | ||
|
||
export default OneTimeSecret; | ||
} | ||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { useState } from 'react'; | ||
import { Copy, Link, AlertCircle } from 'lucide-react'; | ||
|
||
const Home = () => { | ||
const [secret, setSecret] = useState(''); | ||
const [generatedLink, setGeneratedLink] = useState(''); | ||
const [inputEnabled, setInputEnabled] = useState(true); | ||
const [error, setError] = useState(''); | ||
|
||
const handleCreateLink = () => { | ||
const data = secret.trim(); | ||
if (!data.trim()) { | ||
setError('Please enter a secret to create a link.'); | ||
return; | ||
} | ||
|
||
setInputEnabled(false); | ||
|
||
const fetchData = async () => { | ||
const response = await fetch('/api/secret/new', { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ data: data.trim() }), | ||
}); | ||
|
||
if (response.ok) { | ||
const data = await response.json(); | ||
setGeneratedLink(`${window.location.origin}/#${data.id}`); | ||
} else { | ||
setGeneratedLink(''); | ||
setError('An error occurred while creating the secret link. Please refresh and try again.'); | ||
} | ||
}; | ||
|
||
fetchData(); | ||
} | ||
|
||
const handleCopyLink = () => { | ||
navigator.clipboard.writeText(generatedLink); | ||
}; | ||
|
||
return ( | ||
<div className="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800 flex items-center justify-center p-4"> | ||
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-md border border-gray-700"> | ||
<h1 className="text-2xl font-bold text-gray-100 mb-4 text-center">Create One-Time Secret</h1> | ||
<textarea | ||
className="w-full h-32 p-2 border border-gray-600 rounded-md focus:ring-2 focus:ring-purple-500 focus:border-transparent resize-none bg-gray-700 text-gray-100 disabled:opacity-50 disabled:cursor-not-allowed" | ||
placeholder="Enter your secret here..." | ||
value={secret} | ||
onChange={(e) => setSecret(e.target.value)} | ||
disabled={!inputEnabled} | ||
maxLength={10000} | ||
/> | ||
<button | ||
className={`mt-4 w-full bg-purple-600 text-white font-bold py-2 px-4 rounded-md transition duration-300 ease-in-out flex items-center justify-center ${inputEnabled | ||
? 'hover:bg-purple-700 hover:shadow-lg transform hover:-translate-y-0.5' | ||
: 'opacity-50 cursor-not-allowed' | ||
}`} | ||
onClick={handleCreateLink} | ||
disabled={!inputEnabled} | ||
> | ||
<Link className="mr-2" size={18} /> | ||
Create Secret Link | ||
</button> | ||
|
||
{generatedLink && ( | ||
<div className="mt-4"> | ||
<p className="text-sm text-gray-400 mb-2">Your secret link:</p> | ||
<div className="flex items-center bg-gray-700 p-2 rounded-md"> | ||
<input | ||
type="text" | ||
readOnly | ||
value={generatedLink} | ||
className="flex-grow bg-transparent text-sm text-gray-300 focus:outline-none" | ||
/> | ||
<button | ||
onClick={handleCopyLink} | ||
className="ml-2 text-purple-400 hover:text-purple-300 transition duration-300 ease-in-out transform hover:scale-110" | ||
title="Copy to clipboard" | ||
> | ||
<Copy size={18} /> | ||
</button> | ||
</div> | ||
</div> | ||
)} | ||
|
||
{error && ( | ||
<div className="mt-4 bg-red-900 border border-red-700 text-red-100 px-4 py-3 rounded relative" role="alert"> | ||
<div className="flex items-center"> | ||
<AlertCircle className="mr-2" size={18} /> | ||
<span className="block sm:inline pl-2 pr-2">{error}</span> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Home; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { useState } from "react"; | ||
import { Eye, AlertCircle } from "lucide-react"; | ||
|
||
type ViewProps = { | ||
hash: string; | ||
}; | ||
|
||
const View = ({ hash }: ViewProps) => { | ||
const [secret, setSecret] = useState(""); | ||
const [error, setError] = useState(""); | ||
const [isViewing, setIsViewing] = useState(false); | ||
|
||
const fetchSecret = async () => { | ||
const response = await fetch(`/api/secret/${hash}`, { | ||
method: 'POST', | ||
cache: "no-store", | ||
}); | ||
if (response.ok) { | ||
const json: { data: string } = await response.json(); | ||
setSecret(json.data); | ||
} else { | ||
setError("Secret not found or has been deleted."); | ||
} | ||
}; | ||
|
||
const handleViewSecret = () => { | ||
setIsViewing(true); | ||
fetchSecret(); | ||
}; | ||
|
||
return ( | ||
<div className="min-h-screen bg-gradient-to-br from-gray-900 to-gray-800 flex items-center justify-center p-4"> | ||
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-md border border-gray-700"> | ||
{!isViewing ? ( | ||
<div className="text-center flex flex-col"> | ||
<p className="text-gray-300 mb-4"> | ||
Viewing this secret will delete it. | ||
</p> | ||
<button | ||
className="bg-purple-600 text-white font-bold py-2 px-4 rounded-md transition duration-300 ease-in-out flex items-center justify-center hover:bg-purple-700 hover:shadow-lg transform hover:-translate-y-0.5" | ||
onClick={handleViewSecret} | ||
> | ||
<Eye className="mr-2" size={18} /> | ||
View Secret | ||
</button> | ||
</div> | ||
) : ( | ||
<div> | ||
{secret ? ( | ||
<> | ||
<h2 className="text-xl text-gray-100 font-bold mb-2">Your Secret:</h2> | ||
<div className="bg-gray-700 p-4 rounded-md"> | ||
<p className="text-gray-300">{secret}</p> | ||
</div> | ||
</> | ||
) : error ? ( | ||
<div className="mt-4 bg-red-900 border border-red-700 text-red-100 px-4 py-3 rounded relative" role="alert"> | ||
<div className="flex items-center"> | ||
<AlertCircle className="mr-2" size={18} /> | ||
<span className="block sm:inline pl-2 pr-2">{error}</span> | ||
</div> | ||
</div> | ||
) : ( | ||
<p className="text-gray-300">Loading...</p> | ||
)} | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default View; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,7 @@ | ||
import { StrictMode } from 'react' | ||
import { createRoot } from 'react-dom/client' | ||
import App from './App.tsx' | ||
import './index.css' | ||
|
||
createRoot(document.getElementById('root')!).render( | ||
<StrictMode> | ||
<App /> | ||
</StrictMode>, | ||
<App /> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters