sponsor event creation api

This commit is contained in:
mohanmd 2026-06-12 18:04:23 +05:30
parent 57eb9b9ed8
commit f7569cd35a
15 changed files with 201 additions and 93 deletions

View File

@ -110,15 +110,27 @@ public function getCharityEvents(Request $request)
$organization = optional($event->employer)->employerProfile->company_name ?? 'Migrant Support';
}
// Decode charity details if they exist in json
$charityDetails = null;
$content = $event->body;
if (strpos($event->body, '{"type":"Charity"') === 0) {
$decoded = json_decode($event->body, true);
if ($decoded) {
$charityDetails = $decoded;
$content = $decoded['content'] ?? $event->body;
}
}
return [
'id' => $event->id,
'title' => $event->title,
'body' => $event->body,
'type' => $event->type,
'posted_by' => $postedBy,
'organization' => $organization,
'created_at' => $event->created_at->toIso8601String(),
'time_ago' => $event->created_at->diffForHumans(),
'id' => $event->id,
'title' => $event->title,
'body' => $content,
'type' => $event->type,
'posted_by' => $postedBy,
'organization' => $organization,
'created_at' => $event->created_at->toIso8601String(),
'time_ago' => $event->created_at->diffForHumans(),
'charity_details' => $charityDetails,
];
});
@ -164,9 +176,15 @@ public function postCharityEvent(Request $request)
}
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
'title' => 'required|string|max:255',
'body' => 'required|string',
'type' => 'nullable|string|in:charity,info,warning,success',
'title' => 'required|string|max:255',
'body' => 'required|string',
'type' => 'nullable|string|in:charity,info,warning,success',
'event_date' => 'required|string',
'start_time' => 'required|string',
'end_time' => 'required|string',
'provided_items' => 'required|string',
'location_details' => 'required|string',
'location_pin' => 'required|string|url',
]);
if ($validator->fails()) {
@ -178,25 +196,49 @@ public function postCharityEvent(Request $request)
}
try {
$eventTime = $request->start_time . ' - ' . $request->end_time;
$bodyJson = json_encode([
'type' => 'Charity',
'provided_items' => $request->provided_items,
'event_date' => $request->event_date,
'event_time' => $eventTime,
'location_details' => $request->location_details,
'location_pin' => $request->location_pin,
'content' => $request->body,
]);
$event = Announcement::create([
'title' => $request->title,
'body' => $request->body,
'body' => $bodyJson,
'type' => $request->type ?? 'charity',
'sponsor_id' => $sponsor->id,
'status' => 'pending',
]);
// Decode charity details for the response representation
$charityDetails = null;
$content = $event->body;
if (strpos($event->body, '{"type":"Charity"') === 0) {
$decoded = json_decode($event->body, true);
if ($decoded) {
$charityDetails = $decoded;
$content = $decoded['content'] ?? $event->body;
}
}
return response()->json([
'success' => true,
'message' => 'Charity event posted successfully.',
'data' => [
'id' => $event->id,
'title' => $event->title,
'body' => $event->body,
'type' => $event->type,
'posted_by' => $sponsor->full_name,
'organization' => $sponsor->organization_name,
'created_at' => $event->created_at->toIso8601String(),
'id' => $event->id,
'title' => $event->title,
'body' => $content,
'type' => $event->type,
'posted_by' => $sponsor->full_name,
'organization' => $sponsor->organization_name,
'created_at' => $event->created_at->toIso8601String(),
'charity_details' => $charityDetails,
]
], 201);

View File

@ -286,7 +286,13 @@
"type": "object",
"required": [
"title",
"body"
"body",
"event_date",
"start_time",
"end_time",
"provided_items",
"location_details",
"location_pin"
],
"properties": {
"title": {
@ -306,6 +312,32 @@
"success"
],
"example": "charity"
},
"event_date": {
"type": "string",
"format": "date",
"example": "2026-06-15"
},
"start_time": {
"type": "string",
"example": "09:00 AM"
},
"end_time": {
"type": "string",
"example": "04:00 PM"
},
"provided_items": {
"type": "string",
"example": "Free Dental screening, cleanings, and wellness kits"
},
"location_details": {
"type": "string",
"example": "Al Quoz Community Hall, Dubai"
},
"location_pin": {
"type": "string",
"format": "uri",
"example": "https://maps.app.goo.gl/xyz"
}
}
}

View File

@ -66,7 +66,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
{ name: 'Dashboard', translationKey: 'dashboard', href: '/employer/dashboard', icon: LayoutDashboard },
{ name: 'Find Workers', translationKey: 'find_workers', href: '/employer/workers', icon: Search },
{ name: 'Shortlist', translationKey: 'shortlist', href: '/employer/shortlist', icon: Bookmark },
{ name: 'Candidates', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck },
{ name: 'Hired Workers', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck },
{ name: 'Messages', translationKey: 'messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count },
{ name: 'Charity Events', translationKey: 'charity_events', href: '/employer/events', icon: Heart },
{ name: 'Subscription', translationKey: 'subscription', href: '/employer/subscription', icon: CreditCard },
@ -78,7 +78,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
const mobileTabs = [
{ name: 'Search', translationKey: 'search', href: '/employer/workers', icon: Search },
{ name: 'Shortlist', translationKey: 'shortlist', href: '/employer/shortlist', icon: Bookmark },
{ name: 'Candidates', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck },
{ name: 'Hired Workers', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck },
{ name: 'Messages', translationKey: 'messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count },
{ name: 'Profile', translationKey: 'profile', href: '/employer/profile', icon: User },
];

View File

@ -137,7 +137,7 @@ export default function Confirm({ worker }) {
<div className="bg-blue-50/50 p-4 rounded-xl border border-blue-100 flex items-start space-x-3">
<Clock className="w-5 h-5 text-[#185FA5] flex-shrink-0 mt-0.5" />
<p className="text-[11px] text-[#185FA5] font-bold leading-relaxed uppercase tracking-tight">
Once you send this offer, the worker will be notified immediately. You can track the status in your Candidates page.
Once you send this offer, the worker will be notified immediately. You can track the status in your Hired Workers page.
</p>
</div>

View File

@ -40,7 +40,7 @@ export default function Success({ worker }) {
</li>
<li className="flex items-start space-x-3 text-xs font-bold text-slate-700">
<div className="w-5 h-5 bg-white rounded-lg flex items-center justify-center flex-shrink-0 shadow-sm border border-slate-100 text-[#185FA5]">2</div>
<span>You can track their response in your "Candidates" dashboard.</span>
<span>You can track their response in your "Hired Workers" dashboard.</span>
</li>
</ul>
</div>
@ -50,7 +50,7 @@ export default function Success({ worker }) {
href="/employer/candidates"
className="w-full bg-[#185FA5] text-white py-4 rounded-xl font-black text-xs uppercase tracking-widest shadow-xl shadow-blue-500/20 hover:bg-[#144f8a] transition-all flex items-center justify-center space-x-2 group"
>
<span>Go to Candidates</span>
<span>Go to Hired Workers</span>
<Users className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
</Link>

View File

@ -125,8 +125,8 @@ export default function SelectedCandidates({ selectedWorkers }) {
}, [filterLocation, filterJobType, filterAccommodation, filterNationality, filterInCountry, filterVisaType]);
return (
<EmployerLayout title={t('candidates_pipeline', 'Candidates')}>
<Head title={`${t('candidates_pipeline', 'Candidates')} - ${t('employer_portal', 'Employer Portal')}`} />
<EmployerLayout title={t('candidates_pipeline', 'Hired Workers')}>
<Head title={`${t('candidates_pipeline', 'Hired Workers')} - ${t('employer_portal', 'Employer Portal')}`} />
{/* ── Filter Drawer ── */}
<FilterDrawer
@ -134,7 +134,7 @@ export default function SelectedCandidates({ selectedWorkers }) {
onClose={() => setDrawerOpen(false)}
onReset={resetFilters}
activeCount={activeFilterCount}
title="Filter Candidates"
title="Filter Hired Workers"
>
{/* Preferred Location */}
<FilterSection label="Preferred Location">
@ -231,7 +231,7 @@ export default function SelectedCandidates({ selectedWorkers }) {
{/* Header Section */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-black text-slate-900 tracking-tight">{t('candidates_pipeline', 'Candidates')}</h1>
<h1 className="text-2xl font-black text-slate-900 tracking-tight">{t('candidates_pipeline', 'Hired Workers')}</h1>
<p className="text-xs font-medium text-slate-500 mt-1">{t('candidates_pipeline_desc', 'Manage your workforce recruitment pipeline')}</p>
</div>
</div>
@ -379,7 +379,7 @@ export default function SelectedCandidates({ selectedWorkers }) {
<div className="text-base font-bold text-slate-400">{t('no_candidates_found', 'No candidates found')}</div>
{activeFilterCount > 0 && (
<button onClick={resetFilters} className="text-sm font-bold text-[#185FA5] hover:underline">
Clear filters to see all candidates
Clear filters to see all hired workers
</button>
)}
</div>
@ -393,7 +393,7 @@ export default function SelectedCandidates({ selectedWorkers }) {
{/* Footer */}
<div className="px-6 py-4 bg-slate-50/50 border-t border-slate-100 flex items-center justify-between">
<div className="text-[10px] font-bold text-slate-500 uppercase tracking-widest">
Showing <span className="text-slate-700">{filteredWorkers.length}</span> of <span className="text-slate-700">{(selectedWorkers || []).filter(w => w.status !== 'Searching').length}</span> candidates
Showing <span className="text-slate-700">{filteredWorkers.length}</span> of <span className="text-slate-700">{(selectedWorkers || []).filter(w => w.status !== 'Searching').length}</span> hired workers
</div>
<div className="flex items-center space-x-2">
<button className="px-3 py-1.5 bg-white border border-slate-200 text-slate-400 rounded-lg text-[10px] font-black cursor-not-allowed">PREV</button>

View File

@ -161,12 +161,10 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
});
};
const toggleMultiSelect = (item, selectedList, setSelectedList) => {
if (selectedList.includes(item)) {
setSelectedList(selectedList.filter(x => x !== item));
} else {
setSelectedList([...selectedList, item]);
}
const toggleMultiSelect = (item, setSelectedList) => {
setSelectedList(prev =>
prev.includes(item) ? prev.filter(x => x !== item) : [...prev, item]
);
};
const applyPreset = (preset) => {
@ -481,7 +479,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
<FilterCheckboxList
items={filtersMetadata.skills.slice(1).map(s => s.toLowerCase())}
selected={selectedSkills}
onToggle={skill => toggleMultiSelect(skill, selectedSkills, setSelectedSkills)}
onToggle={skill => toggleMultiSelect(skill, setSelectedSkills)}
/>
</FilterSection>
)}
@ -492,7 +490,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
<FilterCheckboxList
items={filtersMetadata.languages.slice(1)}
selected={selectedLanguages}
onToggle={lang => toggleMultiSelect(lang, selectedLanguages, setSelectedLanguages)}
onToggle={lang => toggleMultiSelect(lang, setSelectedLanguages)}
/>
</FilterSection>
)}

View File

@ -185,29 +185,34 @@ export function FilterChips({ options, selected, onChange }) {
);
}
/**
* FilterCheckboxList a list of checkboxes for multi-select.
* items: string[]
*/
export function FilterCheckboxList({ items, selected, onToggle }) {
return (
<div className="space-y-2 max-h-48 overflow-y-auto pr-1">
{items.map(item => (
<label key={item} className="flex items-center space-x-3 cursor-pointer group">
<div className={`w-4 h-4 rounded border-2 flex items-center justify-center flex-shrink-0 transition-all ${
selected.includes(item)
? 'bg-[#185FA5] border-[#185FA5]'
: 'border-slate-300 group-hover:border-[#185FA5]'
}`}>
{selected.includes(item) && (
<svg className="w-2.5 h-2.5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
)}
</div>
<span className="text-sm font-medium text-slate-700 capitalize group-hover:text-slate-900 transition-colors">{item}</span>
</label>
))}
{items.map(item => {
const isChecked = selected.includes(item);
return (
<button
key={item}
type="button"
onClick={() => onToggle(item)}
className="w-full flex items-center space-x-3 text-left focus:outline-none group cursor-pointer"
>
<div className={`w-4 h-4 rounded border-2 flex items-center justify-center flex-shrink-0 transition-all ${
isChecked
? 'bg-[#185FA5] border-[#185FA5]'
: 'border-slate-300 group-hover:border-[#185FA5]'
}`}>
{isChecked && (
<svg className="w-2.5 h-2.5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
)}
</div>
<span className="text-sm font-medium text-slate-700 capitalize group-hover:text-slate-900 transition-colors">{item}</span>
</button>
);
})}
</div>
);
}

View File

@ -2,7 +2,7 @@
"dashboard": "Dashboard",
"find_workers": "Find Workers",
"shortlist": "Shortlist",
"candidates": "Candidates",
"candidates": "Hired Workers",
"messages": "Messages",
"charity_events": "Charity Events",
"subscription": "Subscription",
@ -149,9 +149,9 @@
"invoice_download_desc": "Direct MOHRE Sponsor receipt downloaded in PDF format successfully.",
"corporate_billing_updated": "Corporate billing details updated.",
"invalid_card_format": "Invalid card number format",
"candidates_pipeline": "Candidates",
"candidates_pipeline": "Hired Workers",
"candidates_pipeline_desc": "Manage your workforce recruitment pipeline",
"total_candidates": "Total Candidates",
"total_candidates": "Total Hired Workers",
"reviewing": "Reviewing",
"offer_sent": "Offer Sent",
"hired": "Hired",
@ -164,8 +164,8 @@
"status_header": "Status",
"actions_header": "Actions",
"change_status_label": "Change Status",
"no_candidates_found": "No candidates found",
"showing_candidates": "Showing {start} to {end} of {total} candidates",
"no_candidates_found": "No hired workers found",
"showing_candidates": "Showing {start} to {end} of {total} hired workers",
"account_settings": "Account Settings",
"profile_employer_portal": "Profile - Employer Portal",
"profile_updated_successfully": "Profile updated successfully",
@ -288,7 +288,7 @@
"found_workers_matching": "Found {count} domestic workers matching search",
"direct_sponsoring_active": "MOHRE UAE Direct Sponsoring Active",
"load_more_workers": "Load More Workers",
"no_candidates_matching": "No candidates match your filters",
"no_candidates_matching": "No hired workers match your filters",
"adjust_filters_desc": "Try adjusting your salary limit, adding additional languages, or broadening nationality preferences.",
"reset_filters": "Reset Filters",
"comparing_workers_count": "Comparing Workers ({count} of 3)",

View File

@ -2,7 +2,7 @@
"dashboard": "डैशबोर्ड",
"find_workers": "कामगार खोजें",
"shortlist": "शॉर्टलिस्ट",
"candidates": "उम्मीदवार",
"candidates": "नियुक्त कर्मचारी",
"messages": "संदेश",
"charity_events": "दान कार्यक्रम",
"subscription": "सदस्यता",
@ -149,9 +149,9 @@
"invoice_download_desc": "प्रत्यक्ष एमओएचआरई प्रायोजक रसीद पीडीएफ प्रारूप में सफलतापूर्वक डाउनलोड की गई।",
"corporate_billing_updated": "कॉर्पोरेट बिलिंग विवरण अपडेट किए गए।",
"invalid_card_format": "अमान्य कार्ड नंबर प्रारूप",
"candidates_pipeline": "उम्मीदवार",
"candidates_pipeline": "नियुक्त कर्मचारी",
"candidates_pipeline_desc": "अपनी कार्यबल भर्ती पाइपलाइन प्रबंधित करें",
"total_candidates": "कुल उम्मीदवार",
"total_candidates": "कुल नियुक्त कर्मचारी",
"reviewing": "समीक्षा की जा रही है",
"offer_sent": "प्रस्ताव भेजा गया",
"hired": "काम पर रखा गया",
@ -164,8 +164,8 @@
"status_header": "स्थिति",
"actions_header": "कार्रवाई",
"change_status_label": "स्थिति बदलें",
"no_candidates_found": "कोई उम्मीदवार नहीं मिला",
"showing_candidates": "कुल {total} उम्मीदवारों में से {start} से {end} दिखाए जा रहे हैं",
"no_candidates_found": "कोई नियुक्त कर्मचारी नहीं मिला",
"showing_candidates": "कुल {total} नियुक्त कर्मचारियों में से {start} से {end} दिखाए जा रहे हैं",
"account_settings": "खाता सेटिंग्स",
"profile_employer_portal": "प्रोफाइल - नियोक्ता पोर्टल",
"profile_updated_successfully": "प्रोफ़ाइल सफलतापूर्वक अपडेट की गई",
@ -288,7 +288,7 @@
"found_workers_matching": "खोज से मेल खाते {count} घरेलू कामगार मिले",
"direct_sponsoring_active": "MOHRE यूएई प्रत्यक्ष प्रायोजन सक्रिय",
"load_more_workers": "और कामगार लोड करें",
"no_candidates_matching": "आपके फ़िल्टर से कोई उम्मीदवार मेल नहीं खाता",
"no_candidates_matching": "आपके फ़िल्टर से कोई नियुक्त कर्मचारी मेल नहीं खाता",
"adjust_filters_desc": "अपनी वेतन सीमा को समायोजित करने, अतिरिक्त भाषाएं जोड़ने, या राष्ट्रीयता प्राथमिकताओं को व्यापक बनाने का प्रयास करें।",
"reset_filters": "फ़िल्टर रीसेट करें",
"comparing_workers_count": "कामगारों की तुलना ({count} में से 3)",

View File

@ -2,7 +2,7 @@
"dashboard": "Dashibodi",
"find_workers": "Tafuta Wafanyakazi",
"shortlist": "Orodha fupi",
"candidates": "Watahiniwa",
"candidates": "Wafanyakazi Walioajiriwa",
"messages": "Ujumbe",
"charity_events": "Matukio ya Misaada",
"subscription": "Usajili",
@ -149,9 +149,9 @@
"invoice_download_desc": "Risiti ya moja kwa moja ya Mdhamini wa MOHRE imepakuliwa katika muundo vya PDF kikamilifu.",
"corporate_billing_updated": "Maelezo ya malipo ya kampuni yamesasishwa.",
"invalid_card_format": "Nambari ya kadi sio sahihi",
"candidates_pipeline": "Watahiniwa",
"candidates_pipeline": "Wafanyakazi Walioajiriwa",
"candidates_pipeline_desc": "Dhibiti mfumo wako wa uajiri wa wafanyakazi",
"total_candidates": "Jumla ya Watahiniwa",
"total_candidates": "Jumla ya Wafanyakazi Walioajiriwa",
"reviewing": "Kuhakiki",
"offer_sent": "Ofa Imetumwa",
"hired": "Ameajiriwa",
@ -164,8 +164,8 @@
"status_header": "Hali",
"actions_header": "Vitendo",
"change_status_label": "Badilisha Hali",
"no_candidates_found": "Hakuna watahiniwa waliopatikana",
"showing_candidates": "Inaonyesha watahiniwa {start} hadi {end} kati ya {total}",
"no_candidates_found": "Hakuna wafanyakazi walioajiriwa waliopatikana",
"showing_candidates": "Inaonyesha wafanyakazi walioajiriwa {start} hadi {end} kati ya {total}",
"account_settings": "Mipangilio ya Akaunti",
"profile_employer_portal": "Wasifu - Tovuti ya Mwajiri",
"profile_updated_successfully": "Wasifu umesasishwa kikamilifu",
@ -288,7 +288,7 @@
"found_workers_matching": "Imepata wafanyakazi wa nyumbani {count} wanaolingana na utafutaji",
"direct_sponsoring_active": "Ufadhili wa Moja kwa Moja wa MOHRE UAE Umerejeshwa",
"load_more_workers": "Pakia Wafanyakazi Zaidi",
"no_candidates_matching": "Hakuna watahiniwa wanaolingana na vichujio vyako",
"no_candidates_matching": "Hakuna wafanyakazi walioajiriwa wanaolingana na vichujio vyako",
"adjust_filters_desc": "Jaribu kurekebisha kikomo chako cha mshahara, kuongeza lugha za ziada, au kupanua mapendeleo ya uraia.",
"reset_filters": "Weka upya Vichujio",
"comparing_workers_count": "Kulinganisha Wafanyakazi ({count} kati ya 3)",

View File

@ -2,7 +2,7 @@
"dashboard": "டாஷ்போர்டு",
"find_workers": "பணியாளர்களைக் கண்டறியவும்",
"shortlist": "சுருக்கப்பட்டியல்",
"candidates": "வேட்பாளர்கள்",
"candidates": "பணியமர்த்தப்பட்டவர்கள்",
"messages": "செய்திகள்",
"charity_events": "அறக்கட்டளை நிகழ்வுகள்",
"subscription": "சந்தா",
@ -149,9 +149,9 @@
"invoice_download_desc": "நேரடி MOHRE முதலாளி ரசீது PDF வடிவத்தில் வெற்றிகரமாக பதிவிறக்கம் செய்யப்பட்டது.",
"corporate_billing_updated": "கார்ப்பரேட் பில்லிங் விவரங்கள் புதுப்பிக்கப்பட்டன.",
"invalid_card_format": "தவறான அட்டை எண் வடிவம்",
"candidates_pipeline": "வேட்பாளர்கள்",
"candidates_pipeline": "பணியமர்த்தப்பட்டவர்கள்",
"candidates_pipeline_desc": "உங்கள் பணியாளர் நியமனக் குழாயை நிர்வகிக்கவும்",
"total_candidates": "மொத்த வேட்பாளர்கள்",
"total_candidates": "ஒட்டுமொத்த பணியமர்த்தப்பட்டவர்கள்",
"reviewing": "மதிப்பாய்வு செய்யப்படுகிறது",
"offer_sent": "சலுகை அனுப்பப்பட்டது",
"hired": "பணியமர்த்தப்பட்டார்",
@ -164,8 +164,8 @@
"status_header": "நிலை",
"actions_header": "செயல்கள்",
"change_status_label": "நிலையை மாற்று",
"no_candidates_found": "வேட்பாளர்கள் யாரும் இல்லை",
"showing_candidates": "மொத்த {total} வேட்பாளர்களில் {start} முதல் {end} வரை காட்டுகிறது",
"no_candidates_found": "பணியமர்த்தப்பட்டவர்கள் யாரும் இல்லை",
"showing_candidates": "மொத்த {total} பணியமர்த்தப்பட்டவர்களில் {start} முதல் {end} வரை காட்டுகிறது",
"account_settings": "கணக்கு அமைப்புகள்",
"profile_employer_portal": "சுயவிவரம் - முதலாளி போர்டல்",
"profile_updated_successfully": "சுயவிவரம் வெற்றிகரமாக புதுப்பிக்கப்பட்டது",
@ -288,7 +288,7 @@
"found_workers_matching": "தேடலுக்குப் பொருத்தமான {count} வீட்டுப் பணியாளர்கள் கண்டறியப்பட்டனர்",
"direct_sponsoring_active": "MOHRE யுஏஇ நேரடி ஸ்பான்சர்ஷிப் செயலில் உள்ளது",
"load_more_workers": "மேலும் பணியாளர்களைக் காட்டு",
"no_candidates_matching": "உங்கள் வடிகட்டிகளுடன் பொருந்தும் வேட்பாளர்கள் யாரும் இல்லை",
"no_candidates_matching": "உங்கள் வடிகட்டிகளுடன் பொருந்தும் பணியமர்த்தப்பட்டவர்கள் யாரும் இல்லை",
"adjust_filters_desc": "உங்கள் சம்பள வரம்பை சரிசெய்யவும், கூடுதல் மொழிகளைச் சேர்க்கவும் அல்லது குடியுரிமை விருப்பங்களை விரிவுபடுத்தவும்.",
"reset_filters": "வடிகட்டிகளை மீட்டமை",
"comparing_workers_count": "பணியாளர்களை ஒப்பிடுதல் ({count} இல் 3)",

View File

@ -2,7 +2,7 @@
"dashboard": "Dashboard",
"find_workers": "Maghanap ng mga Manggagawa",
"shortlist": "Shortlist",
"candidates": "Mga Kandidato",
"candidates": "Mga Manggagawang Na-hire",
"messages": "Mga Mensahe",
"charity_events": "Mga Kaganapang Kawanggawa",
"subscription": "Susunod",
@ -149,9 +149,9 @@
"invoice_download_desc": "Matagumpay na na-download ang direktang resibo ng MOHRE Sponsor sa format na PDF.",
"corporate_billing_updated": "Na-update ang mga detalye ng billing ng kumpanya.",
"invalid_card_format": "Maling format ng numero ng card",
"candidates_pipeline": "Mga Kandidato",
"candidates_pipeline": "Mga Manggagawang Na-hire",
"candidates_pipeline_desc": "Pamahalaan ang iyong pipeline ng pangangalap ng mga tauhan",
"total_candidates": "Kabuuang mga Kandidato",
"total_candidates": "Kabuuang mga Manggagawang Na-hire",
"reviewing": "Sinusuri",
"offer_sent": "Naipadala na ang Alok",
"hired": "Na-hire",
@ -164,8 +164,8 @@
"status_header": "Katayuan",
"actions_header": "Mga Aksyon",
"change_status_label": "Baguhin ang Katayuan",
"no_candidates_found": "Walang nahanap na mga kandidato",
"showing_candidates": "Ipinapakita ang {start} hanggang {end} ng {total} na mga kandidato",
"no_candidates_found": "Walang nahanap na mga manggagawang na-hire",
"showing_candidates": "Ipinapakita ang {start} hanggang {end} ng {total} na mga manggagawang na-hire",
"account_settings": "Mga Setting ng Account",
"profile_employer_portal": "Profile - Portal ng Employer",
"profile_updated_successfully": "Matagumpay na na-update ang profile",
@ -288,7 +288,7 @@
"found_workers_matching": "Nakahanap ng {count} na kasambahay na tumutugma sa iyong paghahanap",
"direct_sponsoring_active": "Aktibo ang Direktang Sponsor ng MOHRE UAE",
"load_more_workers": "Mag-load ng Higit Pang Manggagawa",
"no_candidates_matching": "Walang mga kandidatong tumutugma sa iyong mga filter",
"no_candidates_matching": "Walang mga manggagawang na-hire na tumutugma sa iyong mga filter",
"adjust_filters_desc": "Subukang i-adjust ang iyong limitasyon sa sahod, magdagdag ng mga karagdagdang wika, o palawakin ang mga kagustuhan sa nasyonalidad.",
"reset_filters": "I-reset ang mga Filter",
"comparing_workers_count": "Inihahambing ang mga Manggagawa ({count} sa 3)",

View File

@ -184,15 +184,37 @@ public function test_sponsor_can_post_charity_event()
$response = $this->withHeaders([
'Authorization' => 'Bearer sponsor_token_xyz',
])->postJson('/api/sponsors/charity-events', [
'title' => 'Community Ramadan Iftar',
'body' => 'Join us for a free community Iftar gathering at the center.',
'type' => 'charity',
'title' => 'Community Ramadan Iftar',
'body' => 'Join us for a free community Iftar gathering at the center.',
'type' => 'charity',
'event_date' => '2026-06-15',
'start_time' => '09:00 AM',
'end_time' => '04:00 PM',
'provided_items' => 'Free Iftar meals, Water, Dates',
'location_details' => 'Al Quoz Community Center, Dubai',
'location_pin' => 'https://maps.app.goo.gl/xyz',
]);
$response->assertStatus(201)
->assertJson([
'success' => true,
'message' => 'Charity event posted successfully.',
'data' => [
'title' => 'Community Ramadan Iftar',
'body' => 'Join us for a free community Iftar gathering at the center.',
'type' => 'charity',
'posted_by' => 'Test Sponsor',
'organization' => 'Save the Children',
'charity_details' => [
'type' => 'Charity',
'provided_items' => 'Free Iftar meals, Water, Dates',
'event_date' => '2026-06-15',
'event_time' => '09:00 AM - 04:00 PM',
'location_details' => 'Al Quoz Community Center, Dubai',
'location_pin' => 'https://maps.app.goo.gl/xyz',
'content' => 'Join us for a free community Iftar gathering at the center.',
]
]
])
->assertJsonStructure([
'data' => [
@ -203,6 +225,15 @@ public function test_sponsor_can_post_charity_event()
'posted_by',
'organization',
'created_at',
'charity_details' => [
'type',
'provided_items',
'event_date',
'event_time',
'location_details',
'location_pin',
'content',
]
]
]);

View File

@ -23,7 +23,7 @@ export default defineConfig({
port: 5173,
cors: true,
hmr: {
host: '192.168.0.203',
host: '10.150.39.221',
},
watch: {
ignored: ['**/storage/framework/views/**'],