import { Button, Checkbox, DatePicker, FormContainer, FormItem, Input, Notification, Select, Tabs, toast, Upload, } from '@/components/ui' import Dialog from '@/components/ui/Dialog' import DateTimepicker from '@/components/ui/DatePicker/DateTimepicker' import Table from '@/components/ui/Table' import TBody from '@/components/ui/Table/TBody' import Td from '@/components/ui/Table/Td' import Th from '@/components/ui/Table/Th' import THead from '@/components/ui/Table/THead' import Tr from '@/components/ui/Table/Tr' import TabContent from '@/components/ui/Tabs/TabContent' import TabList from '@/components/ui/Tabs/TabList' import TabNav from '@/components/ui/Tabs/TabNav' import { deleteClaimUser, getUserDetail, postClaimUser, putUserAvatar, putUserDetail, putUserLookout, putUserPermission, } from '@/services/identity.service' import { CountryDto, getCountry } from '@/services/home.service' import { useLocalization } from '@/utils/hooks/useLocalization' import dayjs from 'dayjs' import { Field, FieldArray, FieldProps, Form, Formik, FormikHelpers } from 'formik' import { useEffect, useRef, useState } from 'react' import PageTitle from '@/components/shared/PageTitle' import { FaBuilding, FaLockOpen, FaUser, FaFileAlt, FaTrashAlt, FaCheckCircle, FaUserAstronaut, FaEnvelope, FaPhone, FaUserCircle, FaFacebookMessenger, FaTelegramPlane, FaHome, FaUniversity, FaCalendarAlt, FaBriefcase, FaIdCard, FaMapMarkerAlt, FaCity, FaBook, FaHashtag, FaMapPin, FaUserTie, FaFemale, FaHeart, FaExclamationTriangle, FaUsers, FaPlus, } from 'react-icons/fa' import { CircleStencil, Cropper, CropperPreview, CropperPreviewRef, CropperRef, } from 'react-advanced-cropper' import 'react-advanced-cropper/dist/style.css' import { useParams } from 'react-router-dom' import * as Yup from 'yup' import { SelectBoxOption, SelectBoxOptionWithGroup, SelectBoxOptionByNumber } from '@/types/shared' import { AdaptableCard, ConfirmDialog } from '@/components/shared' import { AssignedClaimViewModel, UserInfoViewModel } from '@/proxy/admin/models' import { AVATAR_URL } from '@/constants/app.constant' import { useStoreActions, useStoreState } from '@/store' import { useSetting } from '@/utils/hooks/useSetting' export interface ClaimTypeDto { claimType: string claimValue: string } function UserDetails() { const { userId } = useParams() const { translate } = useLocalization() const [userDetails, setUserDetails] = useState() const [open, setOpen] = useState(false) const [confirmDeleteClaim, setConfirmDeleteClaim] = useState(null) const [countries, setCountries] = useState([]) const [image, setImage] = useState() const [hasAvatarChange, setHasAvatarChange] = useState(false) const cropperRef = useRef(null) const previewRef = useRef(null) const auth = useStoreState((state) => state.auth) const { setUser } = useStoreActions((actions) => actions.auth.user) const { setting } = useSetting() const isEmailUpdateEnabled = setting('Abp.Identity.User.IsEmailUpdateEnabled') const isRequireConfirmedEmail = setting('Abp.Identity.SignIn.RequireConfirmedEmail') const isRequireConfirmedPhoneNumber = setting('Abp.Identity.SignIn.RequireConfirmedPhoneNumber') const isTwoFactorEnabled = setting('Abp.Account.TwoFactor.Enabled') const getUser = async (syncAvatar = true) => { if (!userId) { return } const { data } = await getUserDetail(userId) setUserDetails(data) if (syncAvatar) { setImage(`${AVATAR_URL(data.id, data.tenantId)}?${dayjs().unix()}`) setHasAvatarChange(false) } } useEffect(() => { setUserDetails(undefined) setImage(undefined) setHasAvatarChange(false) getUser() }, [userId]) useEffect(() => { getCountry().then(({ data }) => setCountries(data)) }, []) const scheme = Yup.object().shape({ claimType: Yup.string().required(), claimValue: Yup.string().required(), }) const onChooseImage = async (file: File[]) => { if (file[0]) { setImage(URL.createObjectURL(file[0])) setHasAvatarChange(true) } else { setImage(undefined) setHasAvatarChange(true) } } const beforeUpload = (files: FileList | null, fileList: File[]) => { let valid: string | boolean = true const allowedFileType = ['image/jpeg', 'image/png', 'image/gif'] const maxFileSize = 2000000 if (fileList.length >= 1) { return translate('::App.Profile.OnlyOneFile') } if (files) { for (const f of files) { if (!allowedFileType.includes(f.type)) { valid = translate('::App.Profile.AllowedImageTypes') } else if (f.size >= maxFileSize) { valid = translate('::App.Profile.MaxFileSize') } } } return valid } const getCroppedAvatar = () => new Promise((resolve, reject) => { const canvas = cropperRef.current?.getCanvas({ minHeight: 100, minWidth: 100, maxHeight: 300, maxWidth: 300, }) if (canvas) { canvas.toBlob((blob) => { if (blob) { resolve(blob) } else { reject() } }, 'image/jpeg') } else { resolve(null) } }) const handleSubmit = async ( values: ClaimTypeDto, { setSubmitting }: FormikHelpers, ) => { setSubmitting(true) try { await postClaimUser({ userId, claimType: values.claimType, claimValue: values.claimValue }) toast.push( {translate('::App.Platform.Save')} , { placement: 'bottom-end', }, ) setOpen(false) getUser() } catch { toast.push( {translate('::App.Platform.Error')} , { placement: 'bottom-end', }, ) } finally { setSubmitting(false) } } return userDetails ? ( <> }> {translate('::Abp.Account.General')} }> {translate('::Abp.Identity.Permissions')} }> {translate('::Abp.Identity.User.WorkInformation')} }> {translate('::Abp.Identity.User.IndentityInformation')} }> {translate('::Abp.Identity.User.LockoutManagement')} }> {translate('::App.IdentityManagement.ClaimType')}
{ setSubmitting(true) await putUserDetail({ ...values }) if (values.id === auth.user.id) { setUser({ ...auth.user, name: `${values.name ?? ''} ${values.surname ?? ''}`.trim(), }) } let keepCurrentAvatar = false if (hasAvatarChange) { const avatar = await getCroppedAvatar() const resp = await putUserAvatar({ userId: values.id!, avatar: avatar ? new File([avatar], 'avatar') : undefined, }) if (resp.status === 200) { const avatarUrl = AVATAR_URL(values.id, values.tenantId) + `?${dayjs().unix()}` if (values.id === auth.user.id) { setUser({ ...auth.user, name: `${values.name ?? ''} ${values.surname ?? ''}`.trim(), avatar: avatarUrl, }) } setImage(avatarUrl) setHasAvatarChange(false) keepCurrentAvatar = true } else { const errorMessage = (resp as { error?: { message?: string } })?.error?.message || translate('::App.Platform.Error') toast.push(, { placement: 'bottom-end', }) } } toast.push( {translate('::App.Platform.Save')} , { placement: 'bottom-end', }, ) getUser(!keepCurrentAvatar) setSubmitting(false) }} > {({ isSubmitting, values }) => { return (
{/* Personal Information */}
{translate( '::Abp.Identity.User.UserInformation.ContactInformation', )}
} component={Input} /> } /> } /> } component={Input} /> {({ field, form }: FieldProps) => { const userTypes: SelectBoxOptionByNumber[] = [ { value: 0, label: translate('::Abp.Account.UserType.Internal'), }, { value: 1, label: translate('::Abp.Account.UserType.External'), }, ] return ( o.value === values.nationality, )} onChange={(option) => form.setFieldValue(field.name, option?.value ?? null) } /> ) }} {({ field, form }: FieldProps) => { const educationOptions: SelectBoxOption[] = [ { value: 'İlkokul', label: translate('::App.EducationLevel.Primary'), }, { value: 'Ortaokul', label: translate('::App.EducationLevel.MiddleSchool'), }, { value: 'Lise', label: translate('::App.EducationLevel.HighSchool'), }, { value: 'Ön Lisans', label: translate('::App.EducationLevel.Associate'), }, { value: 'Lisans', label: translate('::App.EducationLevel.Bachelor'), }, { value: 'Yüksek Lisans', label: translate('::App.EducationLevel.Master'), }, { value: 'Doktora', label: translate('::App.EducationLevel.PhD'), }, ] return ( o.value === values.bloodType, )} onChange={(option) => form.setFieldValue(field.name, option?.value ?? null) } /> ) }}
Avatar
{image ? ( { setTimeout(() => { previewRef.current?.update(cropper) }, 100) }} className="cropper max-h-[300px] max-w-[300px]" stencilComponent={CircleStencil} minHeight={100} minWidth={100} /> ) : ( )}
{image && ( )}
) }}
{ setSubmitting(true) await putUserPermission({ ...values }) toast.push( {translate('::Abp.Identity.User.SavePermission')} , { placement: 'bottom-end', }, ) getUser() setSubmitting(false) }} > {({ isSubmitting, values }) => { const roles = values.roles const branches = values.branches return (
{/* Şube Management */}
{translate('::Abp.Identity.User.UserInformation.BranchManagement')}
{() => (
{branches && branches.length > 0 ? branches.map((_, index: number) => (
)) : null}
)}
{/* Role Management */}
{translate('::Abp.Identity.User.UserInformation.RoleManagement')}
{() => (
{roles && roles.length > 0 ? roles.map((_, index: number) => (
)) : null}
)}
) }}
{ setSubmitting(true) await putUserDetail({ ...values }) toast.push( {translate('::App.Platform.Save')} , { placement: 'bottom-end', }, ) getUser() setSubmitting(false) }} > {({ isSubmitting, values }) => { const departments = values.departments const jobPositions = values.jobPositions const departmentOptions: SelectBoxOption[] = departments.map((department) => ({ value: department.id, label: department.name, })) const jobPositionOptions: SelectBoxOptionWithGroup[] = jobPositions.map( (jobPosition) => ({ value: jobPosition.id, label: jobPosition.name, group: jobPosition.departmentId, }), ) return (
{({ field, form }: FieldProps) => ( option.group === values.departmentId, )} isClearable={true} value={jobPositionOptions.filter( (option) => option.value === values.jobPositionId, )} onChange={(option) => form.setFieldValue(field.name, option?.value) } /> )}
} />
} />
} />
{({ field, form }: FieldProps) => ( } onChange={(date) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )}
{({ field, form }: FieldProps) => ( } onChange={(date) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )}
) }}
{ setSubmitting(true) await putUserDetail({ ...values }) toast.push( {translate('::App.Platform.Save')} , { placement: 'bottom-end', }, ) getUser() setSubmitting(false) }} > {({ isSubmitting, values }) => { const maritalStatusOptions: SelectBoxOption[] = [ { value: 'Bekar', label: translate('::App.MaritalStatus.Single'), }, { value: 'Evli', label: translate('::App.MaritalStatus.Married'), }, { value: 'Boşanmış', label: translate('::App.MaritalStatus.Divorced'), }, { value: 'Dul', label: translate('::App.MaritalStatus.Widowed'), }, ] return (
} />
} />
} />
} />
} />
} />
} />
} />
} />
{({ field, form }: FieldProps) => ( } onChange={(date) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )}
} />
{({ field, form }: FieldProps) => ( } onChange={(date) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )}
} />
} />
{({ field, form }: FieldProps) => ( option.value === values.workHour, )} onChange={(option) => form.setFieldValue(field.name, option?.value) } /> )} {({ field, form }: FieldProps) => ( } onChange={(date) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )} {({ field, form }: FieldProps) => ( } onChange={(date: any) => { form.setFieldValue( field.name, date ? dayjs(date).format('YYYY-MM-DDTHH:mm:ss') : null, ) }} /> )} {({ field, form }: FieldProps) => ( } /> )} {({ field, form }: FieldProps) => ( } /> )}
) }}
{userDetails.claims.some((a) => a.isAssigned === true) ? ( userDetails.claims .filter((claim) => claim.isAssigned === true) .map((claim) => ( )) ) : ( )}
{translate('::Abp.Identity.User.ClaimType')} {translate('::Abp.Identity.User.ClaimValue')}
{claim.claimType} {claim.claimValue}
{translate('::Abp.Identity.User.NoClaimsFound')}
setOpen(false)} onRequestClose={() => setOpen(false)}> {({ touched, errors, values, isSubmitting }) => { const claimOptions: SelectBoxOption[] = userDetails?.claims.map((claim) => ({ value: claim.claimType, label: claim.claimType, })) return (
{({ field, form }: FieldProps) => (