Add lock files for package management and update architecture documentation
- Introduced bun.lock and package-lock.json to manage dependencies for the project. - Enhanced backend API architecture documentation with additional security and documentation guidelines. - Made minor formatting adjustments across various files for consistency and clarity.
This commit is contained in:
@@ -4,7 +4,7 @@ import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/c
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, addAsset} from '@/store';
|
||||
import {useAppDispatch, createAsset} from '@/store';
|
||||
import {validatePositiveNumber, validateRequired, sanitizeString} from '@/lib/validation';
|
||||
|
||||
interface Props {
|
||||
@@ -46,12 +46,10 @@ export default function AddAssetDialog({open, onOpenChange}: Props) {
|
||||
if (valueNum === null) return;
|
||||
|
||||
dispatch(
|
||||
addAsset({
|
||||
id: crypto.randomUUID(),
|
||||
createAsset({
|
||||
name: sanitizeString(form.name),
|
||||
type: form.type as (typeof assetTypes)[number],
|
||||
type: form.type.toUpperCase() as 'CASH' | 'INVESTMENT' | 'PROPERTY' | 'VEHICLE' | 'OTHER',
|
||||
value: valueNum,
|
||||
updatedAt: new Date().toISOString()
|
||||
})
|
||||
);
|
||||
onOpenChange(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/c
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, addLiability} from '@/store';
|
||||
import {useAppDispatch, createLiability} from '@/store';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -20,12 +20,10 @@ export default function AddLiabilityDialog({open, onOpenChange}: Props) {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
dispatch(
|
||||
addLiability({
|
||||
id: crypto.randomUUID(),
|
||||
createLiability({
|
||||
name: form.name,
|
||||
type: form.type as (typeof liabilityTypes)[number],
|
||||
balance: parseFloat(form.balance) || 0,
|
||||
updatedAt: new Date().toISOString()
|
||||
type: form.type.toUpperCase() as 'CREDIT_CARD' | 'LOAN' | 'MORTGAGE' | 'OTHER',
|
||||
currentBalance: parseFloat(form.balance) || 0,
|
||||
})
|
||||
);
|
||||
onOpenChange(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/c
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, updateAsset, removeAsset, type Asset} from '@/store';
|
||||
import {useAppDispatch, updateAsset, deleteAsset, type Asset} from '@/store';
|
||||
import {validatePositiveNumber, validateRequired} from '@/lib/validation';
|
||||
|
||||
interface Props {
|
||||
@@ -60,10 +60,11 @@ export default function EditAssetDialog({open, onOpenChange, asset}: Props) {
|
||||
dispatch(
|
||||
updateAsset({
|
||||
id: asset.id,
|
||||
name: form.name.trim(),
|
||||
type: form.type as (typeof assetTypes)[number],
|
||||
value: valueNum,
|
||||
updatedAt: new Date().toISOString()
|
||||
data: {
|
||||
name: form.name.trim(),
|
||||
type: form.type.toUpperCase() as 'CASH' | 'INVESTMENT' | 'PROPERTY' | 'VEHICLE' | 'OTHER',
|
||||
value: valueNum,
|
||||
}
|
||||
})
|
||||
);
|
||||
onOpenChange(false);
|
||||
@@ -72,7 +73,7 @@ export default function EditAssetDialog({open, onOpenChange, asset}: Props) {
|
||||
const handleDelete = () => {
|
||||
if (!asset) return;
|
||||
if (confirm(`Are you sure you want to delete "${asset.name}"?`)) {
|
||||
dispatch(removeAsset(asset.id));
|
||||
dispatch(deleteAsset(asset.id));
|
||||
onOpenChange(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@ import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/c
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, updateLiability, removeLiability, type Liability} from '@/store';
|
||||
import {useAppDispatch, updateLiability, deleteLiability, type Liability} from '@/store';
|
||||
import {validatePositiveNumber, validateRequired} from '@/lib/validation';
|
||||
|
||||
interface Props {
|
||||
@@ -60,10 +60,11 @@ export default function EditLiabilityDialog({open, onOpenChange, liability}: Pro
|
||||
dispatch(
|
||||
updateLiability({
|
||||
id: liability.id,
|
||||
name: form.name.trim(),
|
||||
type: form.type as (typeof liabilityTypes)[number],
|
||||
balance: balanceNum,
|
||||
updatedAt: new Date().toISOString()
|
||||
data: {
|
||||
name: form.name.trim(),
|
||||
type: form.type.toUpperCase() as 'CREDIT_CARD' | 'LOAN' | 'MORTGAGE' | 'OTHER',
|
||||
currentBalance: balanceNum,
|
||||
}
|
||||
})
|
||||
);
|
||||
onOpenChange(false);
|
||||
@@ -72,7 +73,7 @@ export default function EditLiabilityDialog({open, onOpenChange, liability}: Pro
|
||||
const handleDelete = () => {
|
||||
if (!liability) return;
|
||||
if (confirm(`Are you sure you want to delete "${liability.name}"?`)) {
|
||||
dispatch(removeLiability(liability.id));
|
||||
dispatch(deleteLiability(liability.id));
|
||||
onOpenChange(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,8 @@ import {Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, Di
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, setUser} from '@/store';
|
||||
import {useAppDispatch} from '@/store';
|
||||
import {loginUser} from '@/store/slices/userSlice';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -18,26 +19,33 @@ export default function LoginDialog({open, onOpenChange, onSwitchToSignUp}: Prop
|
||||
password: '',
|
||||
});
|
||||
const [error, setError] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
|
||||
// Mock login - in production this would validate against an API
|
||||
if (!form.email || !form.password) {
|
||||
setError('Please enter your email and password');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mock successful login
|
||||
dispatch(setUser({
|
||||
id: crypto.randomUUID(),
|
||||
email: form.email,
|
||||
name: form.email.split('@')[0],
|
||||
}));
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await dispatch(
|
||||
loginUser({
|
||||
email: form.email,
|
||||
password: form.password,
|
||||
})
|
||||
).unwrap();
|
||||
|
||||
onOpenChange(false);
|
||||
setForm({email: '', password: ''});
|
||||
onOpenChange(false);
|
||||
setForm({email: '', password: ''});
|
||||
} catch (err: any) {
|
||||
setError(err || 'Login failed. Please check your credentials.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -76,8 +84,10 @@ export default function LoginDialog({open, onOpenChange, onSwitchToSignUp}: Prop
|
||||
{error && <p className="text-sm text-red-400">{error}</p>}
|
||||
</div>
|
||||
<DialogFooter className="flex-col gap-2 sm:flex-col">
|
||||
<Button type="submit" className="w-full">Log in</Button>
|
||||
<Button type="button" variant="ghost" className="w-full" onClick={onSwitchToSignUp}>
|
||||
<Button type="submit" className="w-full" disabled={isLoading}>
|
||||
{isLoading ? 'Logging in...' : 'Log in'}
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" className="w-full" onClick={onSwitchToSignUp} disabled={isLoading}>
|
||||
Don't have an account? Sign up
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
@@ -3,7 +3,8 @@ import {Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, Di
|
||||
import {Button} from '@/components/ui/button';
|
||||
import {Input} from '@/components/ui/input';
|
||||
import {Label} from '@/components/ui/label';
|
||||
import {useAppDispatch, setUser} from '@/store';
|
||||
import {useAppDispatch} from '@/store';
|
||||
import {registerUser} from '@/store/slices/userSlice';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
@@ -20,8 +21,9 @@ export default function SignUpDialog({open, onOpenChange, onSwitchToLogin}: Prop
|
||||
confirmPassword: '',
|
||||
});
|
||||
const [error, setError] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
|
||||
@@ -30,20 +32,28 @@ export default function SignUpDialog({open, onOpenChange, onSwitchToLogin}: Prop
|
||||
return;
|
||||
}
|
||||
|
||||
if (form.password.length < 6) {
|
||||
setError('Password must be at least 6 characters');
|
||||
if (form.password.length < 8) {
|
||||
setError('Password must be at least 8 characters');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mock sign up - in production this would call an API
|
||||
dispatch(setUser({
|
||||
id: crypto.randomUUID(),
|
||||
email: form.email,
|
||||
name: form.name,
|
||||
}));
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await dispatch(
|
||||
registerUser({
|
||||
email: form.email,
|
||||
password: form.password,
|
||||
name: form.name,
|
||||
})
|
||||
).unwrap();
|
||||
|
||||
onOpenChange(false);
|
||||
setForm({name: '', email: '', password: '', confirmPassword: ''});
|
||||
onOpenChange(false);
|
||||
setForm({name: '', email: '', password: '', confirmPassword: ''});
|
||||
} catch (err: any) {
|
||||
setError(err || 'Registration failed. Please try again.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -109,8 +119,10 @@ export default function SignUpDialog({open, onOpenChange, onSwitchToLogin}: Prop
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter className="flex-col gap-2 sm:flex-col">
|
||||
<Button type="submit" className="w-full">Create account</Button>
|
||||
<Button type="button" variant="ghost" className="w-full" onClick={onSwitchToLogin}>
|
||||
<Button type="submit" className="w-full" disabled={isLoading}>
|
||||
{isLoading ? 'Creating account...' : 'Create account'}
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" className="w-full" onClick={onSwitchToLogin} disabled={isLoading}>
|
||||
Already have an account? Log in
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
Reference in New Issue
Block a user