Mobile ve Desktop IsPopupFullScreen

This commit is contained in:
Sedat ÖZTÜRK 2026-06-11 14:38:48 +03:00
parent a7db340011
commit 0f46de0381
9 changed files with 64 additions and 39 deletions

View file

@ -4,6 +4,7 @@ namespace Sozsoft.Platform.ListForms.DynamicApi;
public class CreateUpdateUserInput public class CreateUpdateUserInput
{ {
public string Avatar { get; set; }
public string UserName { get; set; } public string UserName { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Surname { get; set; } public string Surname { get; set; }

View file

@ -170,6 +170,7 @@ public class PlatformIdentityAppService : ApplicationService
LoginEndDate = user.GetLoginEndDate(), LoginEndDate = user.GetLoginEndDate(),
ConcurrencyStamp = user.ConcurrencyStamp, ConcurrencyStamp = user.ConcurrencyStamp,
LastPasswordChangeTime = user.LastPasswordChangeTime, LastPasswordChangeTime = user.LastPasswordChangeTime,
Avatar = user.GetAvatar(),
EmailConfirmed = user.EmailConfirmed, EmailConfirmed = user.EmailConfirmed,
PhoneNumberConfirmed = user.PhoneNumberConfirmed, PhoneNumberConfirmed = user.PhoneNumberConfirmed,

View file

@ -68,6 +68,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
user.SetDepartmentId(ParseGuid(input.Data.DepartmentId)); user.SetDepartmentId(ParseGuid(input.Data.DepartmentId));
user.SetJobPositionId(ParseGuid(input.Data.JobPositionId)); user.SetJobPositionId(ParseGuid(input.Data.JobPositionId));
user.SetIsVerified(verify); user.SetIsVerified(verify);
user.SetAvatar(input.Data.Avatar);
(await userManager.CreateAsync(user, input.Data.Password)).CheckErrors(); (await userManager.CreateAsync(user, input.Data.Password)).CheckErrors();
await userManager.SetLockoutEnabledAsync(user, true); await userManager.SetLockoutEnabledAsync(user, true);
@ -138,6 +139,12 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
user.SetJobPositionId(ParseGuid(input.Data.JobPositionId)); user.SetJobPositionId(ParseGuid(input.Data.JobPositionId));
} }
if (input.Data.Avatar != null)
{
user.SetJobPositionId(ParseGuid(input.Data.Avatar));
}
(await userManager.UpdateAsync(user)).CheckErrors(); (await userManager.UpdateAsync(user)).CheckErrors();
} }
@ -231,7 +238,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
entity.SetEmail(input.Data.Email); entity.SetEmail(input.Data.Email);
entity.SetWebsite(input.Data.Website); entity.SetWebsite(input.Data.Website);
entity.SetMenuGroup(input.Data.MenuGroup); entity.SetMenuGroup(input.Data.MenuGroup);
await tenantRepository.UpdateAsync(entity, autoSave: true); await tenantRepository.UpdateAsync(entity, autoSave: true);
} }

View file

@ -78,7 +78,7 @@ const FormEdit = (
return ( return (
<> <>
<Container <Container
className={`${isNotePanelVisible && !isSubForm ? 'mr-[400px]' : ''} transition-all duration-300`} className={`${isNotePanelVisible && !isSubForm ? 'lg:mr-[375px]' : ''} transition-all duration-300`}
> >
{!isSubForm && ( {!isSubForm && (
<Helmet <Helmet

View file

@ -74,7 +74,7 @@ const FormView = (
return ( return (
<> <>
<Container <Container
className={`${isNotePanelVisible && !isSubForm ? 'mr-[400px]' : ''} transition-all duration-300`} className={`${isNotePanelVisible && !isSubForm ? 'lg:mr-[375px]' : ''} transition-all duration-300`}
> >
{!isSubForm && ( {!isSubForm && (
<Helmet <Helmet

View file

@ -339,13 +339,13 @@ export const NoteList: React.FC<NoteListProps> = ({
} }
return ( return (
<div className="relative"> <div className="relative min-w-0 overflow-x-hidden">
<Tabs <Tabs
value={currentTab} value={currentTab}
onChange={(val) => setCurrentTab(val as 'notes' | 'audit')} onChange={(val) => setCurrentTab(val as 'notes' | 'audit')}
variant="underline" variant="underline"
> >
<TabList className="mb-2 border-0 dark:bg-gray-800"> <TabList className="mb-2 flex-wrap border-0 dark:bg-gray-800">
<TabNav value="notes"> <TabNav value="notes">
{translate('::ListForms.ListForm.Notes')} {translate('::ListForms.ListForm.Notes')}
<Badge className="ml-2 bg-blue-500" content={`${notes?.length ?? 0}`} /> <Badge className="ml-2 bg-blue-500" content={`${notes?.length ?? 0}`} />
@ -358,7 +358,7 @@ export const NoteList: React.FC<NoteListProps> = ({
<div className="mb-2 flex min-h-10 items-center justify-end border-y border-gray-200 bg-gray-50 px-1 py-1 dark:border-gray-700 dark:bg-gray-900"> <div className="mb-2 flex min-h-10 items-center justify-end border-y border-gray-200 bg-gray-50 px-1 py-1 dark:border-gray-700 dark:bg-gray-900">
{currentTab === 'notes' ? ( {currentTab === 'notes' ? (
<div className="flex items-center gap-2"> <div className="flex flex-wrap items-center justify-end gap-2">
<Button <Button
variant="default" variant="default"
size="xs" size="xs"
@ -404,7 +404,7 @@ export const NoteList: React.FC<NoteListProps> = ({
<p className="text-sm">{translate('::ListForms.ListForm.Notes.Empty')}</p> <p className="text-sm">{translate('::ListForms.ListForm.Notes.Empty')}</p>
</div> </div>
) : ( ) : (
<div className="space-y-5 ml-5"> <div className="space-y-5 pl-7">
{notes.map((note, index) => { {notes.map((note, index) => {
const files = note.filesJson ? JSON.parse(note.filesJson) : [] const files = note.filesJson ? JSON.parse(note.filesJson) : []
const creationDate = note.creationTime ? new Date(note.creationTime) : null const creationDate = note.creationTime ? new Date(note.creationTime) : null
@ -413,7 +413,7 @@ export const NoteList: React.FC<NoteListProps> = ({
return ( return (
<div <div
key={note.id || index} key={note.id || index}
className={`relative bg-white border-l-4 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 dark:bg-gray-900 dark:border-purple-600 ${border}`} className={`relative min-w-0 bg-white border-l-4 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 dark:bg-gray-900 dark:border-purple-600 ${border}`}
> >
{/* Timeline Düğmesi */} {/* Timeline Düğmesi */}
<div className="absolute -left-7 top-4 bg-white rounded-full border-2 border-gray-300 p-2"> <div className="absolute -left-7 top-4 bg-white rounded-full border-2 border-gray-300 p-2">
@ -422,8 +422,8 @@ export const NoteList: React.FC<NoteListProps> = ({
<div className="p-4"> <div className="p-4">
{/* Header */} {/* Header */}
<div className="flex justify-between items-start"> <div className="flex items-start justify-between gap-2">
<div> <div className="min-w-0">
<div className="flex items-center gap-1 text-sm font-semibold text-gray-800 dark:text-gray-200"> <div className="flex items-center gap-1 text-sm font-semibold text-gray-800 dark:text-gray-200">
<Avatar <Avatar
size={25} size={25}
@ -453,7 +453,7 @@ export const NoteList: React.FC<NoteListProps> = ({
</div> </div>
{/* Body */} {/* Body */}
<div className="mt-3 ml-1"> <div className="mt-3 ml-1 break-words">
{note.subject && ( {note.subject && (
<h4 className="text-sm font-bold text-gray-900 mb-1">{note.subject}</h4> <h4 className="text-sm font-bold text-gray-900 mb-1">{note.subject}</h4>
)} )}
@ -503,7 +503,7 @@ export const NoteList: React.FC<NoteListProps> = ({
<p className="text-sm">{translate('::ListForms.ListForm.AuditLogs.Empty')}</p> <p className="text-sm">{translate('::ListForms.ListForm.AuditLogs.Empty')}</p>
</div> </div>
) : ( ) : (
<div className="space-y-4 ml-5"> <div className="space-y-4 pl-7">
{auditItems.map(({ log, matchedActions }) => { {auditItems.map(({ log, matchedActions }) => {
const execTime = log.executionTime ? new Date(log.executionTime) : null const execTime = log.executionTime ? new Date(log.executionTime) : null
const changeCount = log.entityChangeCount ?? log.entityChanges?.length ?? 0 const changeCount = log.entityChangeCount ?? log.entityChanges?.length ?? 0
@ -552,7 +552,7 @@ export const NoteList: React.FC<NoteListProps> = ({
return ( return (
<div <div
key={log.id} key={log.id}
className="relative bg-white border-l-4 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 border-purple-400 dark:bg-gray-900 dark:border-purple-600" className="relative min-w-0 bg-white border-l-4 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 border-purple-400 dark:bg-gray-900 dark:border-purple-600"
> >
<div className="absolute -left-7 top-4 bg-white rounded-full border-2 border-gray-300 p-2"> <div className="absolute -left-7 top-4 bg-white rounded-full border-2 border-gray-300 p-2">
<FaHistory className="text-purple-600" /> <FaHistory className="text-purple-600" />

View file

@ -7,6 +7,8 @@ import { noteService } from '@/services/note.service'
import { NoteDto } from '@/proxy/note/models' import { NoteDto } from '@/proxy/note/models'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
const NOTE_PANEL_WIDTH = 375
interface NotePanelProps { interface NotePanelProps {
entityName: string entityName: string
entityId: string entityId: string
@ -144,18 +146,20 @@ export const NotePanel: React.FC<NotePanelProps> = ({
{/* Panel */} {/* Panel */}
<div <div
className={`fixed right-0 top-0 h-full bg-white border-l border-gray-500 shadow-xl transform transition-transform duration-300 ease-in-out z-30 dark:bg-gray-800 ${isVisible ? 'translate-x-0' : 'translate-x-full'}`} className={`fixed right-0 top-0 h-full max-w-full bg-white border-l border-gray-500 shadow-xl transform transition-transform duration-300 ease-in-out z-30 dark:bg-gray-800 ${isVisible ? 'translate-x-0' : 'translate-x-full'}`}
style={{ width: '450px' }} style={{ width: `min(100vw, ${NOTE_PANEL_WIDTH}px)` }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">
<div className="p-2 border-b border-gray-200 dark:bg-gray-900 dark:border-gray-700"> <div className="p-2 border-b border-gray-200 dark:bg-gray-900 dark:border-gray-700">
{/* Üst Satır: Başlık, Kayıt Bilgisi Toggle ve Kapat Butonu */} {/* Üst Satır: Başlık, Kayıt Bilgisi Toggle ve Kapat Butonu */}
<div className="flex items-center justify-between mx-1 my-1"> <div className="flex items-start justify-between gap-2 mx-1 my-1">
<div className="flex flex-col gap-1 text-sm text-gray-700"> <div className="flex min-w-0 flex-col gap-1 text-sm text-gray-700">
<span className="font-medium text-black dark:text-white">{entityName}</span> <span className="break-words font-medium text-black dark:text-white">
{entityName}
</span>
<code className="py-1 rounded text-gray-800 text-xs font-mono w-fit"> <code className="py-1 rounded text-gray-800 text-xs font-mono break-all">
<Badge className="bg-blue-100 text-blue-600 dark:bg-blue-600 dark:text-blue-100" content={entityId} /> <Badge className="bg-blue-100 text-blue-600 dark:bg-blue-600 dark:text-blue-100" content={entityId} />
</code> </code>
</div> </div>

View file

@ -254,7 +254,7 @@ const Grid = (props: GridProps) => {
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
const { translate } = useLocalization() const { translate } = useLocalization()
const currentUser = useStoreState((state) => state.auth.user) const currentUser = useStoreState((state) => state.auth.user)
const useMobileEditPopup = useRef(isMobileViewport() || isTouchLikeDevice()).current const useMobileEditPopup = isMobileViewport() || isTouchLikeDevice()
const gridRef = useRef<DataGridRef>() const gridRef = useRef<DataGridRef>()
const refListFormCode = useRef('') const refListFormCode = useRef('')
@ -520,7 +520,9 @@ const Grid = (props: GridProps) => {
} }
setMode('new') setMode('new')
setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
e.promise = (async () => { e.promise = (async () => {
const rawFilter = searchParams?.get('filter') const rawFilter = searchParams?.get('filter')
@ -609,7 +611,7 @@ const Grid = (props: GridProps) => {
editingFormDataRef.current = { ...(e.data || {}) } editingFormDataRef.current = { ...(e.data || {}) }
})() })()
}, },
[gridDto, searchParams, extraFilters, getNextSequenceValue], [gridDto, searchParams, extraFilters, getNextSequenceValue, useMobileEditPopup],
) )
const onRowInserting = useCallback( const onRowInserting = useCallback(
@ -659,7 +661,9 @@ const Grid = (props: GridProps) => {
isEditingRef.current = true isEditingRef.current = true
editingFormDataRef.current = { ...(e.data || {}) } editingFormDataRef.current = { ...(e.data || {}) }
setMode('edit') setMode('edit')
setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
const columns = e.component.option('columns') as GridColumnData[] const columns = e.component.option('columns') as GridColumnData[]
// FormEditingExtraItem field ise datayı doldur // FormEditingExtraItem field ise datayı doldur
@ -676,7 +680,7 @@ const Grid = (props: GridProps) => {
e.data[col.dataField] = json[field[1]] e.data[col.dataField] = json[field[1]]
}) })
}, },
[gridDto, mode], [gridDto, mode, useMobileEditPopup],
) )
const onDataErrorOccurred = useCallback((e: DataGridTypes.DataErrorOccurredEvent<any, any>) => { const onDataErrorOccurred = useCallback((e: DataGridTypes.DataErrorOccurredEvent<any, any>) => {
@ -965,9 +969,11 @@ const Grid = (props: GridProps) => {
} }
if (gridDto.gridOptions.editingOptionDto?.popup) { if (gridDto.gridOptions.editingOptionDto?.popup) {
setIsPopupFullScreen(gridDto.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
} }
}, [gridDto]) }, [gridDto, useMobileEditPopup])
// extraFilters değişikliklerini useMemo ile optimize et // extraFilters değişikliklerini useMemo ile optimize et
const filterParams = useMemo(() => { const filterParams = useMemo(() => {
@ -1557,8 +1563,8 @@ const Grid = (props: GridProps) => {
width: useMobileEditPopup width: useMobileEditPopup
? '100%' ? '100%'
: gridDto.gridOptions.editingOptionDto?.popup?.width, : gridDto.gridOptions.editingOptionDto?.popup?.width,
height: useMobileEditPopup height: useMobileEditPopup && isPopupFullScreen
? '100dvh' ? '100%'
: gridDto.gridOptions.editingOptionDto?.popup?.height, : gridDto.gridOptions.editingOptionDto?.popup?.height,
position: useMobileEditPopup position: useMobileEditPopup
? { ? {
@ -1607,7 +1613,7 @@ const Grid = (props: GridProps) => {
? translate('::Normal Boyut') ? translate('::Normal Boyut')
: translate('::Tam Ekran'), : translate('::Tam Ekran'),
stylingMode: 'text', stylingMode: 'text',
onClick: () => setIsPopupFullScreen(!isPopupFullScreen), onClick: () => setIsPopupFullScreen((current) => !current),
}, },
}, },
], ],
@ -1834,7 +1840,7 @@ const Grid = (props: GridProps) => {
<Template name={'cellEditImageUpload'} render={ImageUploadEditorComponent} /> <Template name={'cellEditImageUpload'} render={ImageUploadEditorComponent} />
<Template <Template
name={'cellEditImageViewer'} name={'cellEditImageViewer'}
render={(data) => ( render={(data: any) => (
<ImageViewerEditorComponent <ImageViewerEditorComponent
{...data} {...data}
fallbackFormData={editingFormDataRef.current} fallbackFormData={editingFormDataRef.current}

View file

@ -242,7 +242,7 @@ const Tree = (props: TreeProps) => {
const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props const { listFormCode, searchParams, isSubForm, level, gridDto: extGridDto } = props
const { translate } = useLocalization() const { translate } = useLocalization()
const currentUser = useStoreState((state) => state.auth.user) const currentUser = useStoreState((state) => state.auth.user)
const useMobileEditPopup = useRef(isMobileViewport() || isTouchLikeDevice()).current const useMobileEditPopup = isMobileViewport() || isTouchLikeDevice()
const gridRef = useRef<TreeListRef>() const gridRef = useRef<TreeListRef>()
const refListFormCode = useRef('') const refListFormCode = useRef('')
@ -554,7 +554,9 @@ const Tree = (props: TreeProps) => {
} }
setMode('new') setMode('new')
setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
for (const colFormat of gridDto?.columnFormats) { for (const colFormat of gridDto?.columnFormats) {
if (!colFormat.fieldName) { if (!colFormat.fieldName) {
@ -656,7 +658,9 @@ const Tree = (props: TreeProps) => {
isEditingRef.current = true isEditingRef.current = true
editingFormDataRef.current = { ...(e.data || {}) } editingFormDataRef.current = { ...(e.data || {}) }
setMode('edit') setMode('edit')
setIsPopupFullScreen(gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto?.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
const columns = e.component.option('columns') as GridColumnData[] const columns = e.component.option('columns') as GridColumnData[]
columns?.forEach((col) => { columns?.forEach((col) => {
if (!col.dataField?.includes(':')) { if (!col.dataField?.includes(':')) {
@ -920,7 +924,9 @@ const Tree = (props: TreeProps) => {
} }
if (gridDto.gridOptions.editingOptionDto?.popup) { if (gridDto.gridOptions.editingOptionDto?.popup) {
setIsPopupFullScreen(gridDto.gridOptions.editingOptionDto?.popup?.fullScreen ?? false) setIsPopupFullScreen(
useMobileEditPopup || (gridDto.gridOptions.editingOptionDto?.popup?.fullScreen ?? false),
)
} }
// Set initial expanded row keys // Set initial expanded row keys
@ -929,7 +935,7 @@ const Tree = (props: TreeProps) => {
} else if (gridDto.gridOptions.treeOptionDto?.autoExpandAll) { } else if (gridDto.gridOptions.treeOptionDto?.autoExpandAll) {
setExpandedRowKeys([]) setExpandedRowKeys([])
} }
}, [gridDto]) }, [gridDto, useMobileEditPopup])
useEffect(() => { useEffect(() => {
if (!gridDto) return if (!gridDto) return
@ -1209,8 +1215,8 @@ const Tree = (props: TreeProps) => {
width: useMobileEditPopup width: useMobileEditPopup
? '100%' ? '100%'
: gridDto.gridOptions.editingOptionDto?.popup?.width, : gridDto.gridOptions.editingOptionDto?.popup?.width,
height: useMobileEditPopup height: useMobileEditPopup && isPopupFullScreen
? '100dvh' ? '100%'
: gridDto.gridOptions.editingOptionDto?.popup?.height, : gridDto.gridOptions.editingOptionDto?.popup?.height,
position: useMobileEditPopup position: useMobileEditPopup
? { ? {
@ -1259,7 +1265,7 @@ const Tree = (props: TreeProps) => {
? translate('::Normal Boyut') ? translate('::Normal Boyut')
: translate('::Tam Ekran'), : translate('::Tam Ekran'),
stylingMode: 'text', stylingMode: 'text',
onClick: () => setIsPopupFullScreen(!isPopupFullScreen), onClick: () => setIsPopupFullScreen((current) => !current),
}, },
}, },
], ],
@ -1604,7 +1610,7 @@ const Tree = (props: TreeProps) => {
<Template name={'cellEditGridBox'} render={GridBoxEditorComponent} /> <Template name={'cellEditGridBox'} render={GridBoxEditorComponent} />
<Template <Template
name={'cellEditImageViewer'} name={'cellEditImageViewer'}
render={(data) => ( render={(data: any) => (
<ImageViewerEditorComponent <ImageViewerEditorComponent
{...data} {...data}
fallbackFormData={editingFormDataRef.current} fallbackFormData={editingFormDataRef.current}