{ "ListFormCode": "Sas.DeveloperKit.CustomComponents", "KeyFieldName": "Id", "GeneratedAt": "2026-10-05T06:00:00Z", "Order": 0, "Rows": [ { "Id": "1bca19aa-e144-5e4c-b23b-9eddd4dafd19", "Name": "MyTimesheetWidget", "RoutePath": null, "Description": "Intranet panosu: çalışanın aylık puantajı (seçilen ay) ve yıllık toplamı, fazla mesai sınırı; Puantajım bağlantısı", "IsActive": true, "Dependencies": [], "Code": "// Calisanin kendi puantaj ozeti. Veri Puantajim ekraninin sorgusundan okunur: satir suzmesi\n// (EmployeeId = oturum acan kullanici) ve yetki ListForm'da kalir, bilesen yalnizca toplar.\nconst MONTHLY = 'Hr.MyTimesheet'\n\nconst loadMonths = async () => {\n const response = await apiService.fetchData({\n method: 'GET',\n url: '/api/app/list-form-select/select',\n params: { listFormCode: MONTHLY, take: 500 },\n })\n return response.data?.data ?? []\n}\n\nconst num = (value) => Number(value ?? 0)\nconst format = (value) => {\n const number = num(value)\n return Number.isInteger(number) ? String(number) : number.toFixed(1)\n}\nconst sum = (rows, field) => rows.reduce((total, row) => total + num(row[field]), 0)\nconst periodOf = (row) => num(row.PeriodYear) * 100 + num(row.PeriodMonth)\nconst periodLabel = (period) => `${String(period % 100).padStart(2, '0')}.${Math.floor(period / 100)}`\n\nconst Stat = ({ label, value, className }) => (\n
\n
{value}
\n
{label}
\n
\n)\n\nconst MyTimesheetWidget = () => {\n const [rows, setRows] = useState([])\n const [period, setPeriod] = useState(0)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let active = true\n loadMonths()\n .then((data) => {\n if (!active) return\n const now = new Date()\n const current = now.getFullYear() * 100 + now.getMonth() + 1\n const periods = data.map(periodOf)\n setRows(data)\n setPeriod(periods.includes(current) ? current : Math.max(current, ...periods))\n })\n .catch(() => {})\n .finally(() => active && setLoading(false))\n return () => {\n active = false\n }\n }, [])\n\n const t = (key, params) => translate(`::Sas.DashboardWidget.Timesheet.${key}`, params)\n const periods = [...new Set(rows.map(periodOf))].sort((a, b) => b - a)\n const month = rows.find((row) => periodOf(row) === period) ?? {}\n const yearRows = rows.filter((row) => num(row.PeriodYear) === Math.floor(period / 100))\n const yearOvertime = sum(yearRows, 'OvertimeHours')\n const limit = num(yearRows[0]?.AnnualOvertimeLimit) || 270\n const ratio = Math.min(100, Math.round((yearOvertime / limit) * 100))\n const barColor = ratio >= 100 ? 'bg-red-500' : ratio >= 80 ? 'bg-orange-500' : 'bg-indigo-500'\n\n return (\n
\n
\n
\n \n

\n {translate('::Sas.DashboardWidget.MyTimesheet')}\n

\n
\n {periods.length > 0 && (\n setPeriod(Number(event.target.value))}\n className=\"rounded-md border border-gray-300 bg-white px-2 py-1 text-xs text-gray-700 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200\"\n >\n {periods.map((value) => (\n \n ))}\n \n )}\n
\n
\n {loading ? (\n
...
\n ) : rows.length === 0 ? (\n
{t('NoData')}
\n ) : (\n <>\n
\n \n \n \n 0 ? 'text-orange-500' : 'text-gray-900 dark:text-white'}\n />\n 0 ? 'text-orange-500' : 'text-gray-900 dark:text-white'}\n />\n 0 ? 'text-red-600' : 'text-gray-900 dark:text-white'}\n />\n
\n
\n {t('LeaveDays', { days: format(month.LeaveDays) })}\n {t('SickDays', { days: format(month.SickDays) })}\n {t('HolidayDays', { days: format(num(month.HolidayDays) + num(month.WeeklyOffDays)) })}\n
\n
\n
\n {t('Year', { year: Math.floor(period / 100) })}\n
\n
\n
\n
{format(sum(yearRows, 'NetHours'))}
\n {t('NetHours')}\n
\n
\n
{format(sum(yearRows, 'LateMinutes'))}
\n {t('Late')}\n
\n
\n
{format(sum(yearRows, 'AbsentDays'))}
\n {t('Absent')}\n
\n
\n
\n {t('OvertimeLimit', { used: format(yearOvertime), limit: format(limit) })}\n
\n
\n
\n
\n
\n \n )}\n
\n \n {t('Open')}\n \n
\n
\n
\n )\n}\n\nexport default MyTimesheetWidget\n", "Props": null, "DataSources": [], "SeoTitle": null, "SeoDescription": null, "SeoKeywords": null, "SeoOgImage": null, "SeoCanonicalUrl": null, "SeoNoIndex": true, "SeoIncludeInSitemap": false, "SeoChangeFrequency": null, "SeoPriority": null, "SeoStructuredData": null } ] }