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 string Avatar { get; set; }
public string UserName { get; set; }
public string Name { get; set; }
public string Surname { get; set; }

View file

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

View file

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

View file

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

View file

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

View file

@ -339,13 +339,13 @@ export const NoteList: React.FC<NoteListProps> = ({
}
return (
<div className="relative">
<div className="relative min-w-0 overflow-x-hidden">
<Tabs
value={currentTab}
onChange={(val) => setCurrentTab(val as 'notes' | 'audit')}
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">
{translate('::ListForms.ListForm.Notes')}
<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">
{currentTab === 'notes' ? (
<div className="flex items-center gap-2">
<div className="flex flex-wrap items-center justify-end gap-2">
<Button
variant="default"
size="xs"
@ -404,7 +404,7 @@ export const NoteList: React.FC<NoteListProps> = ({
<p className="text-sm">{translate('::ListForms.ListForm.Notes.Empty')}</p>
</div>
) : (
<div className="space-y-5 ml-5">
<div className="space-y-5 pl-7">
{notes.map((note, index) => {
const files = note.filesJson ? JSON.parse(note.filesJson) : []
const creationDate = note.creationTime ? new Date(note.creationTime) : null
@ -413,7 +413,7 @@ export const NoteList: React.FC<NoteListProps> = ({
return (
<div
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 */}
<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">
{/* Header */}
<div className="flex justify-between items-start">
<div>
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
<div className="flex items-center gap-1 text-sm font-semibold text-gray-800 dark:text-gray-200">
<Avatar
size={25}
@ -453,7 +453,7 @@ export const NoteList: React.FC<NoteListProps> = ({
</div>
{/* Body */}
<div className="mt-3 ml-1">
<div className="mt-3 ml-1 break-words">
{note.subject && (
<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>
</div>
) : (
<div className="space-y-4 ml-5">
<div className="space-y-4 pl-7">
{auditItems.map(({ log, matchedActions }) => {
const execTime = log.executionTime ? new Date(log.executionTime) : null
const changeCount = log.entityChangeCount ?? log.entityChanges?.length ?? 0
@ -552,7 +552,7 @@ export const NoteList: React.FC<NoteListProps> = ({
return (
<div
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">
<FaHistory className="text-purple-600" />

View file

@ -7,6 +7,8 @@ import { noteService } from '@/services/note.service'
import { NoteDto } from '@/proxy/note/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
const NOTE_PANEL_WIDTH = 375
interface NotePanelProps {
entityName: string
entityId: string
@ -144,18 +146,20 @@ export const NotePanel: React.FC<NotePanelProps> = ({
{/* Panel */}
<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'}`}
style={{ width: '450px' }}
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: `min(100vw, ${NOTE_PANEL_WIDTH}px)` }}
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col h-full">
<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 */}
<div className="flex items-center justify-between mx-1 my-1">
<div className="flex flex-col gap-1 text-sm text-gray-700">
<span className="font-medium text-black dark:text-white">{entityName}</span>
<div className="flex items-start justify-between gap-2 mx-1 my-1">
<div className="flex min-w-0 flex-col gap-1 text-sm text-gray-700">
<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} />
</code>
</div>

View file

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

View file

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