Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4bcc03d
added code for google SSO
shubhh139 Oct 16, 2025
50c0655
removed unnecessary files
shubhh139 Oct 16, 2025
027d571
added translation via indictrans2
shubhh139 Oct 17, 2025
ecb3900
Translation API completed
shubhh139 Oct 23, 2025
cc30b5c
api key generation, listing and deletion with X-API key as header for…
shubhh139 Oct 23, 2025
56977e1
README updated
shubhh139 Oct 23, 2025
4b60fa0
added support for auto-detection of source language while translation
shubhh139 Oct 24, 2025
e95e020
Merge branch 'master' of github.com:joshsoftware/zaban into feat/sk/a…
shubhh139 Oct 24, 2025
ee3d289
added auto detection of source language in translation
shubhh139 Oct 30, 2025
759309e
front_end_boiler_plate
naaz-josh Oct 16, 2025
1260ab9
resolved google sso integration
naaz-josh Oct 17, 2025
02ebf35
implement forgot-password UI page
saniyaa7 Oct 20, 2025
a31fbfd
Implemented API Key genration Listing and Modal UI
saniyaa7 Oct 20, 2025
3d4d1ba
removed left section for signin, signup and forgot password page
saniyaa7 Oct 23, 2025
5bb8117
added Speech to Text UI
saniyaa7 Oct 23, 2025
ee4d40d
Implemented API Key genration Listing and Modal UI
saniyaa7 Oct 20, 2025
e56816f
added Speech to Text UI
saniyaa7 Oct 23, 2025
f37d822
Integrate secret key listing, creation and deletion API
saniyaa7 Oct 24, 2025
2ad039d
renamed to 'componenets' to 'components'
saniyaa7 Oct 24, 2025
088817e
updated main.py required to load the .env properly
shubhh139 Nov 3, 2025
5f188c7
stt feature via whisper completed
shubhh139 Nov 5, 2025
a45b11d
stt feature with UI and translation UI completed
shubhh139 Nov 10, 2025
ecc4912
frontend code completed
shubhh139 Nov 10, 2025
f0ff444
Merge branch 'master' into feat/sk/stt_and_tts
shubhh139 Nov 11, 2025
6d53ed6
added dockerfile
shubhh139 Dec 8, 2025
260f5a7
fix: handle error properly and remove the hardcoded value
purisaurabh Dec 9, 2025
80e99aa
fix: format the code
purisaurabh Dec 9, 2025
ec668f5
fix: add .gitignore file
purisaurabh Dec 9, 2025
ec215ae
fix: add hugging face token and indictrans2 model
purisaurabh Dec 9, 2025
cb090ac
Merge branch 'feat/sk/stt_and_tts' of github.com:joshsoftware/zaban i…
purisaurabh Dec 9, 2025
18b6891
Merge branch 'master' of github.com:joshsoftware/zaban into feat/sk/s…
purisaurabh Dec 9, 2025
84851ee
resolved issue for text to speech functionality
shubhh139 Dec 10, 2025
0ae9e7a
Merge branch 'feat/sk/stt_and_tts' of github.com:joshsoftware/zaban i…
shubhh139 Dec 10, 2025
68bd2f7
fix: issue related to playback
purisaurabh Dec 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions frontend/app/components/ApiKeySettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
'use client';

import { useState, useEffect } from 'react';
import { Settings, Eye, EyeOff, Check, AlertCircle, X } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { getSecretApiKey, setSecretApiKey } from '../lib/api-service';

interface ApiKeySettingsProps {
isOpen: boolean;
onClose: () => void;
}

export default function ApiKeySettings({ isOpen, onClose }: ApiKeySettingsProps) {
const [apiKey, setApiKey] = useState('');
const [showKey, setShowKey] = useState(false);
const [saved, setSaved] = useState(false);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
if (isOpen) {
const storedKey = getSecretApiKey();
setApiKey(storedKey || '');
setShowKey(false);
setSaved(false);
setError(null);
}
}, [isOpen]);

// Handle ESC key to close modal
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape' && isOpen) {
onClose();
}
};

if (isOpen) {
document.addEventListener('keydown', handleEscape);
return () => {
document.removeEventListener('keydown', handleEscape);
};
}
}, [isOpen, onClose]);

const handleSave = () => {
if (!apiKey.trim()) {
setError('Please enter an API key');
return;
}

try {
setSecretApiKey(apiKey.trim());
setSaved(true);
setError(null);
setTimeout(() => {
setSaved(false);
onClose();
}, 1500);
} catch (err) {
setError('Failed to save API key');
console.error('Error saving API key:', err);
}
};

const handleClear = () => {
if (window.confirm('Are you sure you want to clear the API key? You will need to set it again to use the services.')) {
setSecretApiKey('');
setApiKey('');
setError(null);
}
};

if (!isOpen) return null;

return (
<AnimatePresence>
{/* Backdrop */}
<motion.div
className="fixed inset-0 bg-black bg-opacity-50 z-40"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
/>

{/* Modal */}
<motion.div
className="fixed inset-0 flex items-center justify-center z-50 p-4"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.2 }}
onClick={(e) => e.stopPropagation()}
>
<div className="bg-white rounded-lg shadow-xl max-w-md w-full p-6 relative">
<button
onClick={onClose}
className="absolute top-4 right-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
type="button"
aria-label="Close modal"
>
<X className="w-5 h-5" />
</button>

<div className="flex items-center gap-3 mb-6 pr-8">
<div className="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center">
<Settings className="w-5 h-5 text-orange-500" />
</div>
<div>
<h3 className="text-xl font-bold text-gray-900">API Key Settings</h3>
<p className="text-sm text-gray-800">Set your secret API key for STT and Translation</p>
</div>
</div>

<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Secret API Key
</label>
<div className="relative">
<input
type={showKey ? 'text' : 'password'}
value={apiKey}
onChange={(e) => {
setApiKey(e.target.value);
setError(null);
setSaved(false);
}}
placeholder="Enter your API key (e.g., sk-...)"
className="w-full px-4 py-3 pr-12 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-transparent transition-all font-mono text-sm"
autoFocus
/>
<button
onClick={() => setShowKey(!showKey)}
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 text-gray-500 hover:text-gray-700"
type="button"
>
{showKey ? (
<EyeOff className="w-5 h-5" />
) : (
<Eye className="w-5 h-5" />
)}
</button>
</div>
<p className="text-xs text-gray-700 mt-2">
This key will be used for Speech-to-Text and Translation API calls.
You can generate one from the API Keys section.
</p>
</div>

{error && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="p-3 bg-red-50 border border-red-200 rounded-lg flex items-start gap-2"
>
<AlertCircle className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5" />
<p className="text-sm text-red-700">{error}</p>
</motion.div>
)}

{saved && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
className="p-3 bg-green-50 border border-green-200 rounded-lg flex items-center gap-2"
>
<Check className="w-5 h-5 text-green-500" />
<p className="text-sm text-green-700">API key saved successfully!</p>
</motion.div>
)}

<div className="flex gap-3 pt-2">
<button
onClick={onClose}
className="flex-1 px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
type="button"
>
Cancel
</button>
<button
onClick={handleClear}
disabled={!apiKey}
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors disabled:bg-gray-100 disabled:cursor-not-allowed disabled:text-gray-400"
type="button"
>
Clear
</button>
<button
onClick={handleSave}
disabled={!apiKey.trim()}
className="flex-1 px-4 py-2 bg-orange-500 text-white rounded-lg hover:bg-orange-600 transition-colors disabled:bg-gray-300 disabled:cursor-not-allowed"
type="button"
>
Save
</button>
</div>
</div>
</div>
</motion.div>
</AnimatePresence>
);
}

Loading