1- import clsx from 'clsx' ;
2- import { useState } from 'react' ;
1+ import { useEffect , useState } from 'react' ;
32import toast from 'react-hot-toast' ;
43
54import { useCompanyGetCurrentPublic } from '../../api/company/useCompanyGetCurrentPublic' ;
@@ -9,106 +8,154 @@ import { Input } from '../../components/Input';
98import { FormComponent } from '../../types/form' ;
109import c from './Accreditation.module.scss' ;
1110
12- const isPersonNameValid = ( person : string ) => {
13- if ( ! person || person . length < 2 || person . length > 50 || / \d / . test ( person ) ) {
14- toast . error ( 'Molimo vas unesite validno ime i prezime' ) ;
15- return false ;
16- }
11+ interface Person {
12+ fullName : string ;
13+ email : string ;
14+ }
1715
18- if ( person . split ( / \s + / ) . length < 2 ) {
19- toast . error ( 'Molimo vas unesite ime i prezime osobe' ) ;
20- return false ;
16+ // Parse stored string format "Name | email" to Person object
17+ const parsePersonString = ( str : string ) : Person => {
18+ const parts = str . split ( ' | ' ) ;
19+ if ( parts . length === 2 ) {
20+ return { fullName : parts [ 0 ] , email : parts [ 1 ] } ;
2121 }
22+ // Fallback for old format (just name)
23+ return { fullName : str , email : '' } ;
24+ } ;
2225
23- return true ;
26+ // Convert Person object to stored string format
27+ const personToString = ( person : Person ) : string => {
28+ return `${ person . fullName } | ${ person . email } ` ;
2429} ;
2530
2631export const Accreditation : FormComponent = ( { close } ) => {
27- const [ personName , setPersonName ] = useState < string > ( '' ) ;
32+ const [ fullName , setFullName ] = useState ( '' ) ;
33+ const [ email , setEmail ] = useState ( '' ) ;
34+ const [ people , setPeople ] = useState < Person [ ] > ( [ ] ) ;
2835
29- const { data : companyData } = useCompanyGetCurrentPublic ( ) ;
36+ const { data : companyData , isLoading , error } = useCompanyGetCurrentPublic ( ) ;
3037 const { mutateAsync : updateAccreditation } = useCompanyUpdateAccreditation ( ) ;
3138 const { mutateAsync : createUser } = useCreateUser ( ) ;
3239
33- const [ people , setPeople ] = useState < string [ ] > (
34- companyData ?. peopleForAccreditation ?? [ ] ,
35- ) ;
40+ useEffect ( ( ) => {
41+ if ( companyData ?. peopleForAccreditation ) {
42+ setPeople ( companyData . peopleForAccreditation . map ( parsePersonString ) ) ;
43+ }
44+ } , [ companyData ] ) ;
45+
46+ if ( error ) return < div > { error . toString ( ) } </ div > ;
47+ if ( isLoading ) return < div > Loading...</ div > ;
3648
3749 const handleAddPerson = ( ) => {
38- if ( ! isPersonNameValid ( personName . trim ( ) ) ) {
50+ const trimmedName = fullName . trim ( ) ;
51+ const trimmedEmail = email . trim ( ) ;
52+
53+ if ( trimmedName . length < 2 || trimmedName . match ( / \d / ) ) {
54+ toast . error ( 'Unesite valjano ime i prezime' ) ;
55+ return ;
56+ }
57+
58+ if ( trimmedName . split ( / \s + / ) . length < 2 ) {
59+ toast . error ( 'Molimo vas unesite ime i prezime osobe' ) ;
3960 return ;
4061 }
4162
42- setPeople ( [ ...people , personName . trim ( ) . replace ( / \s + / g, ' ' ) ] ) ;
43- setPersonName ( '' ) ;
63+ if ( ! / \S + @ \S + \. \S + / . test ( trimmedEmail ) ) {
64+ toast . error ( 'Unesite valjanu email adresu' ) ;
65+ return ;
66+ }
67+
68+ setPeople ( [ ...people , { fullName : trimmedName , email : trimmedEmail } ] ) ;
69+ setFullName ( '' ) ;
70+ setEmail ( '' ) ;
4471 } ;
4572
46- const handleRemovePerson = ( name : string ) => {
47- setPeople ( people . filter ( ( p ) => p != name ) ) ;
73+ const handleRemovePerson = ( emailToRemove : string ) => {
74+ setPeople ( people . filter ( ( p ) => p . email !== emailToRemove ) ) ;
4875 } ;
4976
5077 const handleSave = async ( ) => {
5178 try {
52- await updateAccreditation ( people ) ;
79+ const peopleStrings = people . map ( personToString ) ;
80+ await updateAccreditation ( peopleStrings ) ;
5381
5482 const existingPeople = companyData ?. peopleForAccreditation ?? [ ] ;
55- const newPeople = people . filter ( ( p ) => ! existingPeople . includes ( p ) ) ;
83+ const existingParsed = existingPeople . map ( parsePersonString ) ;
84+ const newPeople = people . filter (
85+ ( p ) => ! existingParsed . some ( ( ep ) => ep . email === p . email ) ,
86+ ) ;
5687
57- newPeople . map ( async ( fullName ) => {
58- const [ firstName , ...lastNameParts ] = fullName . split ( ' ' ) ;
88+ for ( const person of newPeople ) {
89+ const [ firstName , ...lastNameParts ] = person . fullName . split ( ' ' ) ;
5990 const lastName = lastNameParts . join ( ' ' ) ;
6091
61- if ( ! firstName || ! lastName ) return ;
92+ if ( ! firstName || ! lastName ) continue ;
6293
6394 await createUser ( { firstName, lastName } ) ;
95+ }
6496
65- close ( ) ;
66- } ) ;
97+ close ( ) ;
6798 } catch ( error ) {
6899 toast . error ( 'Došlo je do greške pri spremanju akreditacija.' ) ;
69100 console . error ( error ) ;
70101 }
71102 } ;
72103
73104 return (
74- < section className = { c . accreditationSection } >
75- < h1 > Akreditacije</ h1 >
76- < p className = { clsx ( c . yMargin , c . description ) } >
77- Dodajte osobe koje će prisustvovati na DUMP DAYS
78- </ p >
79-
105+ < div className = { c . container } >
80106 < div >
81- < Input
82- value = { personName }
83- label = 'Ime osobe'
84- onChange = { ( value ) => setPersonName ( value ) }
85- />
86-
87- < button
88- onClick = { handleAddPerson }
89- className = { clsx ( c . yMargin , c . button , c . secondary , c . add ) } >
90- Dodaj osobu
91- </ button >
92- </ div >
93-
94- < ul className = { c . personList } >
95- { people . map ( ( person ) => (
96- < li key = { person } className = { c . listItem } >
97- < span className = { c . yMargin } > { person } </ span >
107+ < h1 className = { c . title } > Akreditacije</ h1 >
108+ < p className = { c . description } >
109+ Dodajte osobe koje će prisustvovati na DUMP DAYS
110+ </ p >
111+
112+ < div className = { c . inputContainer } >
113+ < label > Osobe za akreditaciju</ label >
114+
115+ < ul className = { c . personList } >
116+ { people . map ( ( person ) => (
117+ < div key = { person . email } className = { c . personRow } >
118+ < li className = { c . personItem } >
119+ < span > { person . fullName } </ span >
120+ < span style = { { opacity : 0.7 , marginLeft : '8px' } } >
121+ { person . email }
122+ </ span >
123+ </ li >
124+ < button
125+ type = 'button'
126+ onClick = { ( ) => handleRemovePerson ( person . email ) }
127+ className = { c . removePersonButton } >
128+ Ukloni
129+ </ button >
130+ </ div >
131+ ) ) }
132+ </ ul >
133+
134+ < div className = { c . addPersonContainer } >
135+ < div
136+ style = { { display : 'flex' , gap : '16px' , marginBottom : '16px' } } >
137+ < Input
138+ value = { fullName }
139+ onChange = { ( val ) => setFullName ( val ) }
140+ label = 'Ime i prezime'
141+ />
142+ < Input
143+ value = { email }
144+ onChange = { ( val ) => setEmail ( val ) }
145+ label = 'Email'
146+ />
147+ </ div >
98148 < button
99- onClick = { ( ) => handleRemovePerson ( person ) }
100- className = { clsx ( c . button , c . secondary , c . remove ) } >
101- Ukloni
149+ onClick = { handleAddPerson }
150+ className = { ` ${ c . smallButton } ${ c . button } ` } >
151+ Dodaj osobu
102152 </ button >
103- </ li >
104- ) ) }
105- </ ul >
106-
107- < button
108- onClick = { handleSave }
109- className = { clsx ( c . button , c . primary , c . saveButton ) } >
153+ </ div >
154+ </ div >
155+ </ div >
156+ < button onClick = { handleSave } className = { c . button } >
110157 Spremi
111158 </ button >
112- </ section >
159+ </ div >
113160 ) ;
114161} ;
0 commit comments