forked from github/plane
chore: date time attribute
This commit is contained in:
parent
2169ba35a9
commit
a014564d11
@ -1,44 +1,41 @@
|
||||
import { useState } from "react";
|
||||
|
||||
// react-datepicker
|
||||
import ReactDatePicker from "react-datepicker";
|
||||
// types
|
||||
import { Props } from "./types";
|
||||
import { renderDateFormat } from "helpers/date-time.helper";
|
||||
|
||||
const DATE_FORMATS: { [key: string]: string } = {
|
||||
"MM-DD-YYYY": "MM-dd-yyyy",
|
||||
"DD-MM-YYYY": "dd-MM-yyyy",
|
||||
"YYYY-MM-DD": "yyyy-MM-dd",
|
||||
};
|
||||
|
||||
const TIME_FORMATS: { [key: string]: string } = {
|
||||
"12": "hh:mm aa",
|
||||
"24": "HH:mm",
|
||||
};
|
||||
|
||||
export const CustomDateTimeAttribute: React.FC<Props & { value: Date | undefined }> = ({
|
||||
attributeDetails,
|
||||
onChange,
|
||||
value,
|
||||
}) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
||||
const handleUpdateDateTime = (val: string) => {
|
||||
setIsEditing(false);
|
||||
|
||||
onChange(new Date(val));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex-shrink-0">
|
||||
{!isEditing &&
|
||||
(value ? (
|
||||
<div
|
||||
className="cursor-pointer text-xs px-2 py-0.5 bg-custom-background-80 rounded w-min max-w-full whitespace-nowrap outline-none"
|
||||
onClick={() => setIsEditing(true)}
|
||||
>
|
||||
{renderDateFormat(value)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="cursor-pointer text-xs truncate" onClick={() => setIsEditing(true)}>
|
||||
Empty
|
||||
</div>
|
||||
))}
|
||||
{isEditing && (
|
||||
<input
|
||||
type="datetime-local"
|
||||
className="text-xs px-2 py-0.5 bg-custom-background-80 rounded w-full outline-none"
|
||||
defaultValue={value?.toString()}
|
||||
onBlur={(e) => handleUpdateDateTime(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
}) => (
|
||||
<div className="flex-shrink-0">
|
||||
<ReactDatePicker
|
||||
selected={value}
|
||||
onChange={onChange}
|
||||
className="bg-custom-background-80 rounded text-xs px-2.5 py-0.5 outline-none"
|
||||
calendarClassName="!bg-custom-background-80"
|
||||
dateFormat={`${
|
||||
attributeDetails.extra_settings.hide_date
|
||||
? ""
|
||||
: DATE_FORMATS[attributeDetails.extra_settings.date_format] ?? "dd-MM-yyyy"
|
||||
}${
|
||||
attributeDetails.extra_settings.hide_time
|
||||
? ""
|
||||
: ", " + (TIME_FORMATS[attributeDetails.extra_settings.time_format] ?? "HH:mm")
|
||||
}`}
|
||||
showTimeInput={!attributeDetails.extra_settings.hide_time}
|
||||
isClearable={!attributeDetails.is_required}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -45,11 +45,8 @@ export const CustomEmailAttribute: React.FC<Props & { value: string | undefined
|
||||
return (
|
||||
<div className="flex-shrink-0">
|
||||
{!isEditing && (
|
||||
<div
|
||||
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded"
|
||||
onClick={() => setIsEditing(true)}
|
||||
>
|
||||
{value && value !== "" ? value : `Enter ${attributeDetails.display_name}`}
|
||||
<div className="cursor-pointer text-xs truncate" onClick={() => setIsEditing(true)}>
|
||||
{value && value !== "" ? value : "Empty"}
|
||||
</div>
|
||||
)}
|
||||
{isEditing && (
|
||||
|
@ -107,21 +107,19 @@ export const CustomFileAttribute: React.FC<Props & { value: string | undefined }
|
||||
)}
|
||||
<div
|
||||
{...getRootProps()}
|
||||
className={`flex items-center justify-center bg-custom-background-80 text-xs rounded px-2.5 py-0.5 cursor-pointer ${
|
||||
className={`flex items-center bg-custom-background-80 text-xs rounded px-2.5 py-0.5 cursor-pointer truncate w-min max-w-full whitespace-nowrap ${
|
||||
isDragActive ? "bg-custom-primary-100/10" : ""
|
||||
} ${isDragReject ? "bg-red-500/10" : ""}`}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
<span className="">
|
||||
{isDragActive ? (
|
||||
<p>Drop here...</p>
|
||||
) : fileError ? (
|
||||
<p className="text-red-500">{fileError}</p>
|
||||
) : isUploading ? (
|
||||
<p>Uploading...</p>
|
||||
) : (
|
||||
<p>Upload {value && value !== "" ? "new " : ""}file</p>
|
||||
)}
|
||||
<input className="flex-shrink-0" {...getInputProps()} />
|
||||
<span className={`flex-grow truncate text-left ${fileError ? "text-red-500" : ""}`}>
|
||||
{isDragActive
|
||||
? "Drop here..."
|
||||
: fileError
|
||||
? fileError
|
||||
: isUploading
|
||||
? "Uploading..."
|
||||
: `Upload ${value && value !== "" ? "new " : ""}file`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -49,7 +49,7 @@ export const CustomNumberAttribute: React.FC<Props & { value: number | undefined
|
||||
return (
|
||||
<div className="flex-shrink-0">
|
||||
{!isEditing && (
|
||||
<div className="cursor-pointer text-xs" onClick={() => setIsEditing(true)}>
|
||||
<div className="cursor-pointer text-xs truncate flex" onClick={() => setIsEditing(true)}>
|
||||
{value ? (
|
||||
<>
|
||||
{extraSettings?.representation === "bar" ? (
|
||||
@ -79,12 +79,12 @@ export const CustomNumberAttribute: React.FC<Props & { value: number | undefined
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<span className="font-medium">{value}</span>
|
||||
<span className="font-medium truncate">{value}</span>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded"
|
||||
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded w-min whitespace-nowrap flex-grow"
|
||||
onClick={() => setIsEditing(true)}
|
||||
>
|
||||
{value ?? `Enter ${attributeDetails.display_name}`}
|
||||
|
@ -45,10 +45,7 @@ export const CustomTextAttribute: React.FC<Props & { value: string | undefined }
|
||||
return (
|
||||
<div className="flex-shrink-0">
|
||||
{!isEditing && (
|
||||
<div
|
||||
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded"
|
||||
onClick={() => setIsEditing(true)}
|
||||
>
|
||||
<div className="cursor-pointer text-xs truncate" onClick={() => setIsEditing(true)}>
|
||||
{value && value !== "" ? value : `Enter ${attributeDetails.display_name}`}
|
||||
</div>
|
||||
)}
|
||||
|
@ -43,10 +43,7 @@ export const CustomUrlAttribute: React.FC<Props & { value: string | undefined }>
|
||||
return (
|
||||
<div className="flex-shrink-0">
|
||||
{!isEditing && (
|
||||
<div
|
||||
className="cursor-pointer text-xs truncate bg-custom-background-80 px-2.5 py-0.5 rounded"
|
||||
onClick={() => setIsEditing(true)}
|
||||
>
|
||||
<div className="cursor-pointer text-xs truncate" onClick={() => setIsEditing(true)}>
|
||||
{value && value !== "" ? value : `Enter ${attributeDetails.display_name}`}
|
||||
</div>
|
||||
)}
|
||||
|
@ -120,7 +120,7 @@ export const SidebarCustomAttributesList: React.FC<Props> = observer(({ issue })
|
||||
<CustomDateTimeAttribute
|
||||
attributeDetails={attribute}
|
||||
issueId={issue.id}
|
||||
onChange={(val: string) => handleAttributeUpdate(attribute.id, [val])}
|
||||
onChange={(val: Date) => handleAttributeUpdate(attribute.id, [val.toISOString()])}
|
||||
projectId={issue.project}
|
||||
value={attributeValue ? new Date(attributeValue?.[0]?.value ?? "") : undefined}
|
||||
/>
|
||||
|
@ -46,6 +46,8 @@ export const CUSTOM_ATTRIBUTES_LIST: {
|
||||
display_name: "",
|
||||
extra_settings: {
|
||||
date_format: "DD-MM-YYYY",
|
||||
hide_date: false,
|
||||
hide_time: false,
|
||||
time_format: "12",
|
||||
},
|
||||
is_required: false,
|
||||
|
@ -29,7 +29,8 @@
|
||||
.react-datepicker {
|
||||
font-family: "Inter" !important;
|
||||
background-color: rgba(var(--color-background-100)) !important;
|
||||
border: 1px solid rgba(var(--color-background-80)) !important;
|
||||
border: 1px solid rgba(var(--color-border-200)) !important;
|
||||
box-shadow: var(--color-shadow-xs);
|
||||
}
|
||||
|
||||
.react-datepicker__month-container {
|
||||
|
Loading…
Reference in New Issue
Block a user