I'll help you create the IkhaFix app with HTML, CSS, and JavaScript. Here's the implementation:
I'll help you create the IkhaFix app with HTML, CSS, and JavaScript. Here's the implementation:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IkhayaFix - Connect with Qualified Technicians</title>
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--accent: #e74c3c;
--light: #ecf0f1;
--dark: #2c3e50;
--success: #2ecc71;
--warning: #f39c12;
--danger: #e74c3c;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light);
color: var(--dark);
}
header {
background-color: var(--primary);
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 1rem;
}
nav ul li a {
color: white;
text-decoration: none;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.hero {
background-color: var(--secondary);
color: white;
padding: 2rem;
border-radius: 0.5rem;
margin-bottom: 1rem;
text-align: center;
}
.btn {
display: inline-block;
padding: 0.5rem 1rem;
background-color: var(--accent);
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
text-decoration: none;
}
.btn:hover {
opacity: 0.9;
}
.card {
background-color: white;
border-radius: ˝0.5rem;
padding: 1rem;
margin-bottom: 1rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
}
input, select, textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.tech-card {
border: 1px solid #ddd;
border-radius: 0.5rem;
padding: 1rem;
}
.tech-card img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 0.25rem;
}
.rating {
color: var(--warning);
}
footer {
background-color: var(--dark);
color: white;
padding: 1rem;
text-align: center;
margin-top: 1rem;
}
@media (max-width: 768px) {
nav ul {
flex-direction: column;
}
nav ul li {
margin: 0.5rem 0;
}
}
</style>
</head>
<body>
<header>
<div class="logo">IkhayaFix</div>
<nav>
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#post-job">Post Job</a></li>
<li><a href="#find-tech">Find Technician</a></li>
<li><a href="#login">Login</a></li>
</ul>
</nav>
</header>
<div class="container">
<section id="home" class="hero">
<h1>Connect with Qualified Technicians in South Africa</h1>
<p>Find trusted professionals for all your home and business repair needs</p>
<a href="#post-job" class="btn">Post a Job</a>
</section>
<section id="post-job" class="card">
<h2>Post a Job</h2>
<form id="jobForm">
<div class="form-group">
<label for="job-title">Job Title</label>
<input type="text" id="job-title" required>
</div>
<div class="form-group">
<label for="job-type">Job Type</label>
<select id="job-type" required>
<option value="">Select job type</option>
<option value="plumbing">Plumbing</option>
<option value="electrical">Electrical</option>
<option value="carpentry">Carpentry</option>
<option value="painting">Painting</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label for="urgency">Urgency</label>
<select id="urgency" required>
<option value="emergency">Emergency (within 2 hours)</option>
<option value="today">Same Day</option>
<option value="scheduled">Scheduled</option>
</select>
</div>
<div class="form-group">
<label for="location">Location</label>
<input type="text" id="location" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" rows="4" required></textarea>
</div>
<div class="form-group">
<label for="photos">Upload Photos (Optional)</label>
<input type="file" id="photos" multiple>
</div>
<button type="submit" class="btn">Post Job</button>
</form>
</section>
<section id="find-tech" class="card">
<h2>Find Technicians</h2>
<div class="grid" id="techGrid">
<!-- Technician cards will be populated here -->
</div>
</section>
</div>
<footer>
<p>© 2023 IkhayaFix. All rights reserved.</p>
</footer>
<script>
// Sample technician data
const technicians = [
{
id: 1,
name: "John Smith",
profession: "Plumber",
skills: ["Geyser repair", "Pipe installation", "Leak detection"],
location: "Cape Town",
rating: 4.8,
available: true,
image: "https://via.placeholder.com/300x200?text=Plumber"
},
{
id: 2,
name: "Sarah Johnson",
profession: "Electrician",
skills: ["Wiring", "Switchboard installation", "Load shedding solutions"],
location: "Johannesburg",
rating: 4.9,
available: true,
image: "https://via.placeholder.com/300x200?text=Electrician"
},
{
id: 3,
name: "Michael Brown",
profession: "Carpenter",
skills: ["Furniture repair", "Door installation", "Custom woodwork"],
location: "Durban",
rating: 4.7,
available: false,
image: "https://via.placeholder.com/300x200?text=Carpenter"
}
];
// Populate technician grid
const techGrid = document.getElementById('techGrid');
technicians.forEach(tech => {
const card = document.createElement('div');
card.className = 'tech-card';
card.innerHTML = `
<img src="${tech.image}" alt="${tech.name}">
<h3>${tech.name}</h3>
<p><strong>Profession:</strong> ${tech.profession}</p>
<p><strong>Location:</strong> ${tech.location}</p>
<p><strong>Skills:</strong> ${tech.skills.join(', ')}</p>
<p class="rating">Rating: ${tech.rating}/5</p>
<p>${tech.available ? 'Available now' : 'Currently unavailable'}</p>
<button class="btn" onclick="bookTechnician(${tech.id})">Book Now</button>
`;
techGrid.appendChild(card);
});
// Job form submission
document.getElementById('jobForm').addEventListener('submit', function(e) {
e.preventDefault();
const jobTitle = document.getElementById('job-title').value;
const jobType = document.getElementById('job-type').value;
const urgency = document.getElementById('urgency').value;
const location = document.getElementById('location').value;
const description = document.getElementById('description').value;
alert(`Job posted successfully!\n\nTitle: ${jobTitle}\nType: ${jobType}\nUrgency: ${urgency}\nLocation: ${location}\nDescription: ${description}`);
// In a real app, you would send this data to a server
});
// Book technician function
function bookTechnician(id) {
const tech = technicians.find(t => t.id === id);
alert(`Booking request sent to ${tech.name} (${tech.profession})`);
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IkhayaFix - Connect with Qualified Technicians</title>
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--accent: #e74c3c;
--light: #ecf0f1;
--dark: #2c3e50;
--success: #2ecc71;
--warning: #f39c12;
--danger: #e74c3c;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light);
color: var(--dark);
}
header {
background-color: var(--primary);
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 1rem;
}
nav ul li a {
color: white;
text-decoration: none;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.hero {
background-color: var(--secondary);
color: white;
padding: 2rem;
border-radius: 0.5rem;
margin-bottom: 1rem;
text-align: center;
}
.btn {
display: inline-block;
padding: 0.5rem 1rem;
background-color: var(--accent);
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
text-decoration: none;
}
.btn:hover {
opacity: 0.9;
}
.card {
background-color: white;
border-radius: ˝0.5rem;
padding: 1rem;
margin-bottom: 1rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 1rem;
}
label {
display: block;
margin-bottom: 0.5rem;
}
input, select, textarea {
width: 100%;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.tech-card {
border: 1px solid #ddd;
border-radius: 0.5rem;
padding: 1rem;
}
.tech-card img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 0.25rem;
}
.rating {
color: var(--warning);
}
footer {
background-color: var(--dark);
color: white;
padding: 1rem;
text-align: center;
margin-top: 1rem;
}
@media (max-width: 768px) {
nav ul {
flex-direction: column;
}
nav ul li {
margin: 0.5rem 0;
}
}
</style>
</head>
<body>
<header>
<div class="logo">IkhayaFix</div>
<nav>
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#post-job">Post Job</a></li>
<li><a href="#find-tech">Find Technician</a></li>
<li><a href="#login">Login</a></li>
</ul>
</nav>
</header>
<div class="container">
<section id="home" class="hero">
<h1>Connect with Qualified Technicians in South Africa</h1>
<p>Find trusted professionals for all your home and business repair needs</p>
<a href="#post-job" class="btn">Post a Job</a>
</section>
<section id="post-job" class="card">
<h2>Post a Job</h2>
<form id="jobForm">
<div class="form-group">
<label for="job-title">Job Title</label>
<input type="text" id="job-title" required>
</div>
<div class="form-group">
<label for="job-type">Job Type</label>
<select id="job-type" required>
<option value="">Select job type</option>
<option value="plumbing">Plumbing</option>
<option value="electrical">Electrical</option>
<option value="carpentry">Carpentry</option>
<option value="painting">Painting</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label for="urgency">Urgency</label>
<select id="urgency" required>
<option value="emergency">Emergency (within 2 hours)</option>
<option value="today">Same Day</option>
<option value="scheduled">Scheduled</option>
</select>
</div>
<div class="form-group">
<label for="location">Location</label>
<input type="text" id="location" required>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" rows="4" required></textarea>
</div>
<div class="form-group">
<label for="photos">Upload Photos (Optional)</label>
<input type="file" id="photos" multiple>
</div>
<button type="submit" class="btn">Post Job</button>
</form>
</section>
<section id="find-tech" class="card">
<h2>Find Technicians</h2>
<div class="grid" id="techGrid">
<!-- Technician cards will be populated here -->
</div>
</section>
</div>
<footer>
<p>© 2023 IkhayaFix. All rights reserved.</p>
</footer>
<script>
// Sample technician data
const technicians = [
{
id: 1,
name: "John Smith",
profession: "Plumber",
skills: ["Geyser repair", "Pipe installation", "Leak detection"],
location: "Cape Town",
rating: 4.8,
available: true,
image: "https://via.placeholder.com/300x200?text=Plumber"
},
{
id: 2,
name: "Sarah Johnson",
profession: "Electrician",
skills: ["Wiring", "Switchboard installation", "Load shedding solutions"],
location: "Johannesburg",
rating: 4.9,
available: true,
image: "https://via.placeholder.com/300x200?text=Electrician"
},
{
id: 3,
name: "Michael Brown",
profession: "Carpenter",
skills: ["Furniture repair", "Door installation", "Custom woodwork"],
location: "Durban",
rating: 4.7,
available: false,
image: "https://via.placeholder.com/300x200?text=Carpenter"
}
];
// Populate technician grid
const techGrid = document.getElementById('techGrid');
technicians.forEach(tech => {
const card = document.createElement('div');
card.className = 'tech-card';
card.innerHTML = `
<img src="${tech.image}" alt="${tech.name}">
<h3>${tech.name}</h3>
<p><strong>Profession:</strong> ${tech.profession}</p>
<p><strong>Location:</strong> ${tech.location}</p>
<p><strong>Skills:</strong> ${tech.skills.join(', ')}</p>
<p class="rating">Rating: ${tech.rating}/5</p>
<p>${tech.available ? 'Available now' : 'Currently unavailable'}</p>
<button class="btn" onclick="bookTechnician(${tech.id})">Book Now</button>
`;
techGrid.appendChild(card);
});
// Job form submission
document.getElementById('jobForm').addEventListener('submit', function(e) {
e.preventDefault();
const jobTitle = document.getElementById('job-title').value;
const jobType = document.getElementById('job-type').value;
const urgency = document.getElementById('urgency').value;
const location = document.getElementById('location').value;
const description = document.getElementById('description').value;
alert(`Job posted successfully!\n\nTitle: ${jobTitle}\nType: ${jobType}\nUrgency: ${urgency}\nLocation: ${location}\nDescription: ${description}`);
// In a real app, you would send this data to a server
});
// Book technician function
function bookTechnician(id) {
const tech = technicians.find(t => t.id === id);
alert(`Booking request sent to ${tech.name} (${tech.profession})`);
}
</script>
</body>
</html>
This implementation includes:
To expand this into a full application, you would need to:
Would you like me to expand on any specific part of this implementation?*
I'll create a comprehensive device-compatible website for IkhayaFix with all the requested features. Here's the implementation:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IkhayaFix - Connect with Qualified Technicians in South Africa</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--accent: #e74c3c;
--light: #ecf0f1;
--dark: #2c3e50;
--success: #2ecc71;
--warning: #f39c12;
--danger: #e74c3c;
--gold: #FFD700;
--silver: #C0C0C0;
--bronze: #CD7F32;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light);
color: var(--dark);
line-height: 1.6;
}
header {
background-color: var(--primary);
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
position: sticky;
top: 0;
z-index: 100;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
display: flex;
align-items: center;
}
.logo img {
height: 40px;
margin-right: 10px;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 1rem;
}
nav ul li a {
color: white;
text-decoration: none;
padding: 0.5rem;
border-radius: 0.25rem;
transition: background-color 0.3s;
}
nav ul li a:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.hero {
background-color: var(--secondary);
color: white;
padding: 2rem;
border-radius: 0.5rem;
margin-bottom: 1rem;
text-align: center;
background-image: url('https://via.placeholder.com/1200x400');
background-size: cover;
background-position: center;
position: relative;
}
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, ˝0.5);
border-radius: 0.5rem;
}
.hero-content {
position: relative;
z-index: 1;
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: var(--accent);
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
text-decoration: none;
font-weight: bold;
transition: all 0.3s;
margin: 0.5rem;
}
.btn:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.btn-secondary {
background-color: var(--secondary);
}
.btn-outline {
background-color: transparent;
border: 2px solid white;
}
.card {
background-color: white;
border-radius: 0.5rem;
padding: 1.5rem;
margin-bottom: 1rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input, select, textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
font-size: 1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.tech-card {
border: 1px solid #ddd;
border-radius: 0.5rem;
padding: 1.5rem;
transition: transform 0.3s, box-shadow 0.3s;
}
.tech-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.tech-card img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
.rating {
color: var(--warning);
font-weight: bold;
}
.badge {
display: inline-block;
padding: 0.25rem 0.5rem;
background-color: var(--secondary);
color: white;
border-radius: 1rem;
font-size: 0.75rem;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
}
.badge-primary {
background-color: var(--primary);
}
.badge-success {
background-color: var(--success);
}
.badge-warning {
background-color: var(--warning);
}
.badge-danger {
background-color: var(--danger);
}
.badge-gold {
background-color: var(--gold);
color: var(--dark);
}
.badge-silver {
background-color: var(--silver);
color: var(--dark);
}
.badge-bronze {
background: var(--bronze);
color: white;
}
.availability {
display: flex;
align-items: center;
margin: 0.5rem 0;
}
.availability .dot {
width: 10px;
height: 10px;
border-radius: 50%;
margin*
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IkhayaFix - Connect with Qualified Technicians in South Africa</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--accent: #e74c3c;
--light: #ecf0f1;
--dark: #2c3e50;
--success: #2ecc71;
--warning: #f39c12;
--danger: #e74c3c;
--gold: #FFD700;
--silver: #C0C0C0;
--bronze: #CD7F32;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--light);
color: var(--dark);
line-height: 1.6;
}
header {
background-color: var(--primary);
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
position: sticky;
top: 0;
z-index: 100;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
display: flex;
align-items: center;
}
.logo img {
height: 40px;
margin-right: 10px;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 1rem;
}
nav ul li a {
color: white;
text-decoration: none;
padding: 0.5rem;
border-radius: 0.25rem;
transition: background-color 0.3s;
}
nav ul li a:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 1rem;
}
.hero {
background-color: var(--secondary);
color: white;
padding: 2rem;
border-radius: 0.5rem;
margin-bottom: 1rem;
text-align: center;
background-image: url('https://via.placeholder.com/1200x400');
background-size: cover;
background-position: center;
position: relative;
}
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, ˝0.5);
border-radius: 0.5rem;
}
.hero-content {
position: relative;
z-index: 1;
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
background-color: var(--accent);
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
text-decoration: none;
font-weight: bold;
transition: all 0.3s;
margin: 0.5rem;
}
.btn:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.btn-secondary {
background-color: var(--secondary);
}
.btn-outline {
background-color: transparent;
border: 2px solid white;
}
.card {
background-color: white;
border-radius: 0.5rem;
padding: 1.5rem;
margin-bottom: 1rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
input, select, textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
font-size: 1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.tech-card {
border: 1px solid #ddd;
border-radius: 0.5rem;
padding: 1.5rem;
transition: transform 0.3s, box-shadow 0.3s;
}
.tech-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.tech-card img {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
.rating {
color: var(--warning);
font-weight: bold;
}
.badge {
display: inline-block;
padding: 0.25rem 0.5rem;
background-color: var(--secondary);
color: white;
border-radius: 1rem;
font-size: 0.75rem;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
}
.badge-primary {
background-color: var(--primary);
}
.badge-success {
background-color: var(--success);
}
.badge-warning {
background-color: var(--warning);
}
.badge-danger {
background-color: var(--danger);
}
.badge-gold {
background-color: var(--gold);
color: var(--dark);
}
.badge-silver {
background-color: var(--silver);
color: var(--dark);
}
.badge-bronze {
background: var(--bronze);
color: white;
}
.availability {
display: flex;
align-items: center;
margin: 0.5rem 0;
}
.availability .dot {
width: 10px;
height: 10px;
border-radius: 50%;
margin*