Spaces:
Running
Running
File size: 5,393 Bytes
cb35b04 08d910b cb35b04 08d910b ac75820 cb35b04 ac75820 cb35b04 ac75820 08d910b cb35b04 ac75820 08d910b ac75820 08d910b cb35b04 ac75820 08d910b ac75820 08d910b cb35b04 08d910b ac75820 08d910b cb35b04 ac75820 08d910b ac75820 08d910b ac75820 cb35b04 ac75820 08d910b ac75820 08d910b ac75820 cb35b04 ac75820 08d910b ac75820 08d910b ac75820 08d910b cb35b04 08d910b cb35b04 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | import { useState, type ChangeEvent } from 'react';
import { uploadMedia } from '../../services/api';
import type { FullProfile } from '../../types';
interface BasicProfileFormProps {
profile: FullProfile;
onChange: (profile: FullProfile) => void;
}
function BasicProfileForm({ profile, onChange }: BasicProfileFormProps) {
const [isUploading, setIsUploading] = useState(false);
const [uploadMessage, setUploadMessage] = useState('');
const [uploadError, setUploadError] = useState('');
const updateField = (field: keyof FullProfile, value: string | undefined) => {
onChange({
...profile,
[field]: value,
});
};
const handleProfileImageUpload = async (event: ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
event.target.value = '';
if (!file) return;
setIsUploading(true);
setUploadMessage('');
setUploadError('');
try {
const paths = await uploadMedia(file);
const imagePath = paths.find((path) => /\.(png|jpg|jpeg|webp|gif)$/i.test(path));
if (!imagePath) {
setUploadError('Upload completed, but no image path was returned.');
return;
}
updateField('profile_image_path', imagePath);
setUploadMessage('Profile image uploaded and selected.');
} catch (error) {
setUploadError(error instanceof Error ? error.message : 'Failed to upload profile image.');
} finally {
setIsUploading(false);
}
};
return (
<section className="admin-section clean">
<div className="admin-form-toolbar">
<div>
<h2>Basic Profile</h2>
<p className="admin-muted">
Edit the public identity, profile image, title, location, tagline, and bio.
</p>
</div>
</div>
<div className="admin-profile-image-panel">
<div>
<h3>Profile Image</h3>
<p className="admin-muted">
Upload a portrait image. The saved path appears in the public hero section.
</p>
<div className="admin-profile-image-actions">
<label className="admin-file-button">
{isUploading ? 'Uploading...' : 'Upload Profile Image'}
<input
type="file"
accept="image/png,image/jpeg,image/webp,image/gif"
onChange={handleProfileImageUpload}
disabled={isUploading}
/>
</label>
<button
className="admin-secondary-button"
type="button"
onClick={() => updateField('profile_image_path', '')}
disabled={!profile.profile_image_path}
>
Remove Image
</button>
</div>
<label className="admin-image-path-field">
Profile Image Path
<input
type="text"
value={profile.profile_image_path ?? ''}
onChange={(event) => updateField('profile_image_path', event.target.value)}
placeholder="/media/projects/images/profile.webp"
/>
</label>
</div>
<div className="admin-profile-image-preview">
{profile.profile_image_path ? <img src={profile.profile_image_path} alt="Profile preview" /> : <span>H7</span>}
</div>
</div>
{uploadMessage && <p className="admin-success">{uploadMessage}</p>}
{uploadError && <p className="admin-error">{uploadError}</p>}
<div className="admin-form-grid">
<label>
Internal Full Name
<input
type="text"
value={profile.name ?? ''}
onChange={(event) => updateField('name', event.target.value)}
placeholder="H. K. Chamira Hashan"
/>
</label>
<label>
Public Display Name
<input
type="text"
value={profile.display_name ?? ''}
onChange={(event) => updateField('display_name', event.target.value)}
placeholder="Chamira Hashan"
/>
</label>
<label className="wide">
Role / Title
<input
type="text"
value={profile.role ?? ''}
onChange={(event) => updateField('role', event.target.value)}
placeholder="Aspiring Backend & AI/ML Developer | Software Engineering Background"
/>
</label>
<label>
Location
<input
type="text"
value={profile.location ?? ''}
onChange={(event) => updateField('location', event.target.value)}
placeholder="Sri Lanka"
/>
</label>
<label>
Tagline
<input
type="text"
value={profile.tagline ?? ''}
onChange={(event) => updateField('tagline', event.target.value)}
placeholder="Building practical backend, AI/ML, and full-stack software projects."
/>
</label>
<label className="wide">
Bio
<textarea
className="admin-json-editor compact tall"
value={profile.bio ?? ''}
onChange={(event) => updateField('bio', event.target.value)}
placeholder="Short professional bio..."
/>
</label>
</div>
</section>
);
}
export default BasicProfileForm;
|