turash/bugulma/frontend/components/add-organization/AddOrganizationWizard.tsx
Damir Mukimov 6347f42e20
Consolidate repositories: Remove nested frontend .git and merge into main repository
- Remove nested git repository from bugulma/frontend/.git
- Add all frontend files to main repository tracking
- Convert from separate frontend/backend repos to unified monorepo
- Preserve all frontend code and development history as tracked files
- Eliminate nested repository complexity for simpler development workflow

This creates a proper monorepo structure with frontend and backend
coexisting in the same repository for easier development and deployment.
2025-11-25 06:02:57 +01:00

144 lines
5.1 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext.tsx';
import { useCreateOrganization } from '@/hooks/api/useOrganizationsAPI.ts';
import { useCreateResourceFlow } from '@/hooks/api/useResourcesAPI.ts';
import { useCreateSite } from '@/hooks/api/useSitesAPI.ts';
import { useOrganizationWizard } from '@/hooks/features/useOrganizationWizard.ts';
import { useTranslation } from '@/hooks/useI18n.tsx';
import { convertNeedsAndOffersToResourceFlows } from '@/lib/resource-flow-mapper.ts';
import { OrganizationFormData } from '@/types.ts';
import ErrorMessage from '@/components/ui/ErrorMessage.tsx';
import Wizard from '@/components/wizard/Wizard.tsx';
import WizardContent from '@/components/add-organization/WizardContent.tsx';
import WizardFooter from '@/components/add-organization/WizardFooter.tsx';
interface AddOrganizationWizardProps {
isOpen: boolean;
onClose: () => void;
}
const AddOrganizationWizard = ({ isOpen, onClose }: AddOrganizationWizardProps) => {
const { t } = useTranslation();
const { isAuthenticated } = useAuth();
const navigate = useNavigate();
const [error, setError] = useState<string | null>(null);
const createOrgMutation = useCreateOrganization();
const createSiteMutation = useCreateSite();
const createResourceFlowMutation = useCreateResourceFlow();
// Redirect to login if not authenticated
useEffect(() => {
if (isOpen && !isAuthenticated) {
navigate('/login');
onClose();
}
}, [isOpen, isAuthenticated, navigate, onClose]);
const onSuccess = useCallback(
async (data: OrganizationFormData) => {
try {
setError(null);
// Step 1: Create organization (backend API only accepts basic fields)
const orgPayload = {
name: data.name,
sector: data.sector,
description: data.description,
subtype: data.subtype,
website: data.website || '',
address: data.address
? `${data.address.street}, ${data.address.city}, ${data.address.state} ${data.address.zip}`.trim()
: '',
logoUrl: data.logoUrl || '',
galleryImages: data.galleryImages || [],
};
const newOrg = await createOrgMutation.mutateAsync(orgPayload);
if (!newOrg?.ID) {
throw new Error('Failed to create organization');
}
// Step 2: Create a default Site for the organization
const sitePayload = {
name: `${data.name} - Main Site`,
address: orgPayload.address,
latitude: data.location.lat,
longitude: data.location.lng,
owner_organization_id: newOrg.ID,
};
const newSite = await createSiteMutation.mutateAsync(sitePayload);
if (!newSite?.ID) {
throw new Error('Failed to create site');
}
// Step 3: Convert user-friendly needs/offers to ResourceFlows and create them
const resourceFlows = convertNeedsAndOffersToResourceFlows(data, newOrg.ID, newSite.ID);
// Create all ResourceFlows in parallel
await Promise.all(
resourceFlows.map((flow) => createResourceFlowMutation.mutateAsync(flow))
);
onClose();
navigate('/map');
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : 'Failed to create organization';
setError(errorMessage);
console.error('Error creating organization:', error);
}
},
[createOrgMutation, createSiteMutation, createResourceFlowMutation, onClose, navigate]
);
const { wizardState, form, smartFill, descriptionGeneration, actions } = useOrganizationWizard({
onSuccess,
});
// Track previous isOpen value to detect when it changes from true to false
const prevIsOpenRef = useRef(isOpen);
// Reset form and wizard state when dialog closes (transitions from open to closed)
useEffect(() => {
if (prevIsOpenRef.current && !isOpen) {
actions.resetWizard();
}
prevIsOpenRef.current = isOpen;
}, [isOpen, actions]);
return (
<>
{error && (
<div className="mb-4">
<ErrorMessage message={error} />
</div>
)}
<Wizard isOpen={isOpen} onClose={onClose} title={t('addOrgWizard.title')}>
<WizardContent
currentStep={wizardState.currentStep}
form={form}
onSmartFill={smartFill.extractFromText}
onManualFill={wizardState.nextStep}
isParsing={smartFill.isExtractingFromText}
parseError={null}
generateDescription={descriptionGeneration.generateDescription}
isGenerating={descriptionGeneration.isGeneratingDescription}
/>
{wizardState.currentStep > 1 && (
<WizardFooter
isFirstStep={wizardState.isFirstStep}
isLastStep={wizardState.isLastStep}
onBack={wizardState.prevStep}
onNext={actions.handleNext}
onSubmit={form.handleSubmit(actions.onSubmit)}
isValid={form.formState.isValid}
/>
)}
</Wizard>
</>
);
};
export default AddOrganizationWizard;