Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 10 additions & 10 deletions .firebase/hosting.YnVpbGQ.cache
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
favicorn.svg,1755761307597,e80dddc27b301efdf9e44c2df1952423ea4b443d9ef1fe22f4bbc3797a0f7a73
asset-manifest.json,1769145784811,7003c3de58911ea083c6b4c996323b85197ee04ff75892bc1d4c0f641015a522
robots.txt,1755761307597,b2090cf9761ef60aa06e4fab97679bd43dfa5e5df073701ead5879d7c68f1ec5
prodhub.svg,1755761307597,c9ccf834f48ca21eaeda0f5566073e9f6757b1e14aaf82591d5afd1486ac39ba
manifest.json,1755761307597,4368aeaf848ae2e048765562c289452f33ad2a175c4b1951ea8bdf2ada0d5b10
static/js/main.ed1316f0.js.LICENSE.txt,1769145784829,016d7efb946774a48216c296cff20c2b87a782bac74ad8d5a1808a48879486df
index.html,1769145784811,8bc49c33b64813d87cf40385c7a8716995325053ca57701670095b2d5687e12b
static/css/main.4409151e.css.map,1769145784827,7dd7f69674e3cf47346aebcac1862d1851d6f1e9fb45159a938e2918f8ee8cfc
logo512.png,1755761307597,212b102aa09e51b3b3e06647e81f7801a61333e171f6582e8124379aabccb41d
logo192.png,1755761307597,79e2b749561016bc8af300ea19f48347ceed3cb1a54f48ae456172eca45e08f0
static/css/main.4409151e.css,1769145784827,5d4ab4f8c7df3fafa8c4bcbf5364d12f6628b371e2cccd12c5d5e03252317ccc
favicorn.svg,1755761307597,e80dddc27b301efdf9e44c2df1952423ea4b443d9ef1fe22f4bbc3797a0f7a73
favicon.ico,1755761307597,27edce7be5922cf0bef7d4136f69b5bfbdd5bf8c13c7b026f71187d41a00aa7d
logo512.png,1755761307597,212b102aa09e51b3b3e06647e81f7801a61333e171f6582e8124379aabccb41d
prodhub.svg,1755761307597,c9ccf834f48ca21eaeda0f5566073e9f6757b1e14aaf82591d5afd1486ac39ba
static/js/main.ed1316f0.js,1769145784829,9b44dbd94b84b0732dbff34210e2d2e9a9ab671ba9f29182eed7949187977881
static/js/main.ed1316f0.js.map,1769145784830,438f6987590f4ffea01fb79415dd8fe340f043f1ae9aa7cbc0c8ac4975d8779c
index.html,1769584165848,7586066520dd701ac52e9e90bddbe8ca563f3019a8e1e4c9b6eff2907821ad1d
static/js/main.1a6ef1f3.js.LICENSE.txt,1769584165861,016d7efb946774a48216c296cff20c2b87a782bac74ad8d5a1808a48879486df
asset-manifest.json,1769584165848,c9c029a4709b7926190cebbb694f56283bad2f51b8a734a11de36bf9ab4b1563
static/css/main.4409151e.css.map,1769584165863,7dd7f69674e3cf47346aebcac1862d1851d6f1e9fb45159a938e2918f8ee8cfc
static/css/main.4409151e.css,1769584165861,5d4ab4f8c7df3fafa8c4bcbf5364d12f6628b371e2cccd12c5d5e03252317ccc
static/js/main.1a6ef1f3.js,1769584165863,ac21c3362d716d7f51e1d0dd96d61a5f29e7f8f8de21bbd8de6593c502891438
static/js/main.1a6ef1f3.js.map,1769584165870,2f58d5fb3ea4a1e82669952fbae4763de61875ee5f32a2e7f394538648e6eee0
1,525 changes: 94 additions & 1,431 deletions src/App.js

Large diffs are not rendered by default.

1,453 changes: 0 additions & 1,453 deletions src/App2.js

This file was deleted.

1,089 changes: 0 additions & 1,089 deletions src/App_v1.js

This file was deleted.

109 changes: 109 additions & 0 deletions src/components/auth/LoginScreen.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { useState } from 'react';

export default function LoginScreen({ onGoogleSignIn, onEmailSignIn, onEmailSignUp }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [isSigningUp, setIsSigningUp] = useState(false);

const handleGoogleSignIn = async () => {
try {
await onGoogleSignIn();
} catch (err) {
setError(err.message);
console.error('Google Sign-In Error:', err);
}
};

const handleEmailAuth = async (e) => {
e.preventDefault();
setError('');
try {
if (isSigningUp) {
await onEmailSignUp(email, password);
} else {
await onEmailSignIn(email, password);
}
} catch (err) {
setError(err.message);
}
};

return (
<div className="flex items-center justify-center h-screen bg-gray-900 text-white">
<div className="w-full max-w-md p-8 space-y-6 bg-gray-800 rounded-lg shadow-lg">
<div className="text-center">
<h1 className="text-3xl font-bold text-blue-400">Welcome to ProdHub</h1>
<p className="text-gray-400">Sign in to continue</p>
</div>
<button
onClick={handleGoogleSignIn}
className="w-full flex items-center justify-center gap-3 py-3 px-4 bg-red-600 hover:bg-red-700 rounded-md font-semibold transition-colors"
>
<svg className="w-6 h-6" viewBox="0 0 48 48">
<path
fill="#EA4335"
d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
></path>
<path
fill="#4285F4"
d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"
></path>
<path
fill="#FBBC05"
d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"
></path>
<path
fill="#34A853"
d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"
></path>
<path fill="none" d="M0 0h48v48H0z"></path>
</svg>
Sign in with Google
</button>
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-600"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-gray-800 text-gray-500">Or continue with</span>
</div>
</div>
<form onSubmit={handleEmailAuth} className="space-y-4">
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
{error && <p className="text-red-400 text-sm text-center">{error}</p>}
<button
type="submit"
className="w-full py-2 px-4 bg-blue-600 hover:bg-blue-700 rounded-md font-semibold transition-colors"
>
{isSigningUp ? 'Sign Up' : 'Sign In'}
</button>
</form>
<p className="text-center text-sm text-gray-400">
{isSigningUp ? 'Already have an account?' : "Don't have an account?"}
<button
onClick={() => setIsSigningUp(!isSigningUp)}
className="font-medium text-blue-400 hover:underline ml-1"
>
{isSigningUp ? 'Sign In' : 'Sign Up'}
</button>
</p>
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions src/components/layout/ConfigurationNeeded.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { Info } from 'lucide-react';

export default function ConfigurationNeeded({ missingFirebase, missingGoogle }) {
return (
<div className="flex items-center justify-center h-screen bg-gray-900 text-white p-8">
<div className="bg-yellow-900/50 border border-yellow-700 rounded-lg p-8 max-w-2xl text-center">
<Info size={48} className="text-yellow-300 mx-auto mb-4" />
<h1 className="text-3xl font-bold text-yellow-200 mb-4">Configuration Required</h1>
{missingFirebase && (
<div className="text-left bg-gray-800 p-4 rounded-md mb-4">
<p className="text-gray-300 mb-2">
<strong>Firebase Config Missing:</strong> Please ensure your Firebase environment variables (REACT_APP_FIREBASE_*) are set correctly in your <code>.env.local</code> file.
</p>
</div>
)}
{missingGoogle && (
<div className="text-left bg-gray-800 p-4 rounded-md">
<p className="text-gray-300 mb-2">
<strong>Google Client ID Missing:</strong> Please ensure REACT_APP_GOOGLE_CLIENT_ID is set in your <code>.env.local</code> file to enable Google Calendar sync.
</p>
</div>
)}
</div>
</div>
);
}
35 changes: 35 additions & 0 deletions src/components/modals/AiContextModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useState } from 'react';

export default function AiContextModal({ isOpen, onClose, onConfirm }) {
const [context, setContext] = useState('');

const handleConfirm = () => {
onConfirm(context);
setContext('');
};

if (!isOpen) return null;

return (
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50">
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-lg mx-4">
<h2 className="text-2xl font-bold text-white mb-4">Add Extra Context</h2>
<p className="text-gray-300 mb-4">Provide any additional details or instructions for the AI to generate more relevant tasks.</p>
<textarea
value={context}
onChange={(e) => setContext(e.target.value)}
placeholder="e.g., Focus on the marketing aspects..."
className="w-full h-24 bg-gray-700 border border-gray-600 rounded-md p-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<div className="flex justify-end gap-4 mt-6">
<button onClick={onClose} className="px-4 py-2 rounded-md bg-gray-600 hover:bg-gray-700 font-semibold transition-colors">
Cancel
</button>
<button onClick={handleConfirm} className="px-4 py-2 rounded-md bg-purple-600 hover:bg-purple-700 font-semibold text-white transition-colors">
Generate Tasks
</button>
</div>
</div>
</div>
);
}
27 changes: 27 additions & 0 deletions src/components/modals/ConfirmModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';

export default function ConfirmModal({ isOpen, onClose, onConfirm, title, message }) {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50">
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-md mx-4">
<h2 className="text-2xl font-bold text-white mb-4">{title}</h2>
<p className="text-gray-300 mb-6">{message}</p>
<div className="flex justify-end gap-4">
<button
onClick={onClose}
className="px-4 py-2 rounded-md bg-gray-600 hover:bg-gray-700 font-semibold transition-colors"
>
Cancel
</button>
<button
onClick={onConfirm}
className="px-4 py-2 rounded-md bg-red-600 hover:bg-red-700 font-semibold text-white transition-colors"
>
Confirm
</button>
</div>
</div>
</div>
);
}
45 changes: 45 additions & 0 deletions src/components/modals/DailyPlannerModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';

export default function DailyPlannerModal({ isOpen, onClose, plan, isLoading, error, retry }) {
if (!isOpen) return null;

return (
<div className="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50 p-4">
<div className="bg-gray-800 rounded-lg shadow-xl p-6 w-full max-w-2xl max-h-[90vh] flex flex-col">
<div className="flex justify-between items-center mb-4">
<h2 className="text-2xl font-bold text-white">Your Daily Plan</h2>
<button onClick={onClose} className="p-1 text-gray-400 hover:text-white">
<span aria-hidden>X</span>
</button>
Comment on lines +11 to +13
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For UI consistency, consider using the X icon from lucide-react for the close button, as was done in the previous version of this component. This will make the look and feel of all modals more uniform. You'll need to add import { X } from 'lucide-react'; at the top of the file.

Suggested change
<button onClick={onClose} className="p-1 text-gray-400 hover:text-white">
<span aria-hidden>X</span>
</button>
<button onClick={onClose} className="p-1 text-gray-400 hover:text-white">
<X size={24} />
</button>

</div>
<div className="overflow-y-auto flex-grow pr-2">
{isLoading && (
<div className="flex flex-col items-center justify-center h-64">
<div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500 mb-4"></div>
<p className="text-lg text-gray-300">Your AI assistant is planning your day...</p>
</div>
)}
{error && (
<div className="text-center h-64 flex flex-col justify-center items-center">
<p className="text-red-400 mb-4">Error: {error}</p>
<button onClick={retry} className="px-4 py-2 rounded-md bg-blue-600 hover:bg-blue-700 font-semibold transition-colors">
Try Again
</button>
</div>
)}
{plan && (
<div
className="text-gray-300 whitespace-pre-wrap font-mono text-sm leading-relaxed"
dangerouslySetInnerHTML={{ __html: plan.replace(/\n/g, '<br />') }}
></div>
)}
</div>
<div className="flex justify-end mt-6">
<button onClick={onClose} className="px-4 py-2 rounded-md bg-gray-600 hover:bg-gray-700 font-semibold transition-colors">
Close
</button>
</div>
</div>
</div>
);
}
Loading