Skip to content

Commit

Permalink
Convert PageForm components to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
elektronaut committed Apr 23, 2023
1 parent 38ee92f commit 123cc42
Show file tree
Hide file tree
Showing 32 changed files with 654 additions and 581 deletions.
82 changes: 21 additions & 61 deletions app/assets/builds/pages_core/admin-dist.js

Large diffs are not rendered by default.

12 changes: 3 additions & 9 deletions app/assets/builds/pages_core/admin-dist.js.map

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import List from "./Attachments/List";

import { AttachmentRecord, Locale } from "../types";
import { useDragCollection } from "./drag";

export default function Attachments(props) {
interface AttachmentsProps {
attribute: string,
locale: string,
locales: { [index: string]: Locale },
records: AttachmentRecord[],
showEmbed: boolean
}

export default function Attachments(props: AttachmentsProps) {
const { attribute, locale, locales, records, showEmbed } = props;

const collection = useDragCollection(records);
Expand All @@ -20,11 +28,3 @@ export default function Attachments(props) {
showEmbed={showEmbed} />
);
}

Attachments.propTypes = {
attribute: PropTypes.string,
locale: PropTypes.string,
locales: PropTypes.object,
records: PropTypes.array,
showEmbed: PropTypes.bool
};
Original file line number Diff line number Diff line change
@@ -1,41 +1,55 @@
import React from "react";
import PropTypes from "prop-types";
import Attachment from "./Attachment";
import Placeholder from "./Placeholder";
import FileUploadButton from "../FileUploadButton";
import { post } from "../../lib/request";

import { AttachmentRecord, AttachmentResource, Locale } from "../../types";

import { createDraggable,
draggedOrder,
useDragUploader } from "../drag";
useDragUploader,
Draggable,
DragCollection,
DragState } from "../drag";

interface ListProps {
attribute: string,
locale: string,
locales: { [index: string]: Locale },
collection: DragCollection,
deleted: AttachmentRecord[],
setDeleted: (records: AttachmentRecord[]) => void,
showEmbed: boolean
}

function filenameToName(str) {
function filenameToName(str: string): string {
return str.replace(/\.[\w\d]+$/, "").replace(/_/g, " ");
}

export default function List(props) {
export default function List(props: ListProps) {
const { collection, deleted, setDeleted } = props;
const locales = props.locales && props.locales.length > 0 ?
Object.keys(props.locales) : [props.locale];

const uploadAttachment = (file) => {
let name = {};
const uploadAttachment = (file: File) => {
const name = {};
locales.forEach((l) => name[l] = file.name);

const draggable = createDraggable(
{ attachment: { filename: file.name, name: name },
uploading: true }
);

let data = new FormData();
const data = new FormData();

data.append("attachment[file]", file);
locales.forEach((l) => {
data.append(`attachment[name][${l}]`, filenameToName(file.name));
});

post("/admin/attachments.json", data)
.then(json => {
void post("/admin/attachments.json", data)
.then((json: AttachmentResource) => {
collection.dispatch({
type: "update",
payload: { ...draggable,
Expand All @@ -46,14 +60,14 @@ export default function List(props) {
return draggable;
};

const receiveFiles = (files) => {
const receiveFiles = (files: File[]) => {
collection.dispatch({
type: "append",
payload: files.map(f => uploadAttachment(f))
});
};

const dragEnd = (dragState, files) => {
const dragEnd = (dragState: DragState, files: File[]) => {
collection.dispatch({
type: "reorder",
payload: draggedOrder(collection, dragState)
Expand All @@ -68,16 +82,16 @@ export default function List(props) {
dragStart,
listeners] = useDragUploader([collection], dragEnd);

const position = (record) => {
const position = (record: AttachmentRecord) => {
return [...collection.draggables.map(d => d.record),
...deleted].indexOf(record) + 1;
};

const attrName = (record) => {
const attrName = (record: AttachmentRecord) => {
return `${props.attribute}[${position(record)}]`;
};

const update = (draggable) => (attachment) => {
const update = (draggable: Draggable<AttachmentRecord>) => (attachment: AttachmentResource) => {
const { record } = draggable;
const updated = {
...draggable,
Expand All @@ -89,14 +103,14 @@ export default function List(props) {
collection.dispatch({ type: "update", payload: updated });
};

const remove = (draggable) => () => {
const remove = (draggable: Draggable) => () => {
collection.dispatch({ type: "remove", payload: draggable });
if (draggable.record.id) {
setDeleted([...deleted, draggable.record]);
}
};

const attachment = (draggable) => {
const attachment = (draggable: Draggable) => {
const { dragging } = dragState;

if (draggable === "Files") {
Expand Down Expand Up @@ -154,13 +168,3 @@ export default function List(props) {
</div>
);
}

List.propTypes = {
attribute: PropTypes.string,
locale: PropTypes.string,
locales: PropTypes.object,
collection: PropTypes.array,
deleted: PropTypes.array,
setDeleted: PropTypes.func,
showEmbed: PropTypes.bool
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import React, { useState } from "react";
import PropTypes from "prop-types";

import DateTimeSelect from "./DateTimeSelect";

function defaultDate(offset = 0) {
let coeff = 1000 * 60 * 60;
interface DateRangeSelectProps {
startsAt: string,
endsAt: string,
disabled: boolean,
disableTime: boolean,
objectName: string
}

function defaultDate(offset = 0): Date {
const coeff = 1000 * 60 * 60;
return new Date(
(Math.round((new Date()).getTime() / coeff) * coeff) + coeff +
(1000 * 60 * offset)
);
}

function parseDate(str) {
function parseDate(str: string): Date {
if (!str) {
return null;
} else if (typeof(str) === "string") {
Expand All @@ -21,27 +28,27 @@ function parseDate(str) {
}
}

export default function DateRangeSelect(props) {
export default function DateRangeSelect(props: DateRangeSelectProps) {
const { disabled, disableTime, objectName } = props;

const [startsAt, setStartsAt] =
useState(parseDate(props.startsAt) || defaultDate());
const [endsAt, setEndsAt] =
useState(parseDate(props.endsAt) || defaultDate(60));

const setDates = (start, end) => {
const setDates = (start: Date, end: Date) => {
if (end < start) {
end = start;
}
setStartsAt(start);
setEndsAt(end);
};

const changeStartsAt = (newDate) => {
const changeStartsAt = (newDate: Date) => {
setDates(newDate, new Date(endsAt.getTime() + (newDate - startsAt)));
};

const changeEndsAt = (newDate) => {
const changeEndsAt = (newDate: Date) => {
setDates(startsAt, newDate);
};

Expand All @@ -67,11 +74,3 @@ export default function DateRangeSelect(props) {
</div>
);
}

DateRangeSelect.propTypes = {
startsAt: PropTypes.string,
endsAt: PropTypes.string,
disabled: PropTypes.bool,
disableTime: PropTypes.bool,
objectName: PropTypes.string
};
Original file line number Diff line number Diff line change
@@ -1,46 +1,67 @@
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";

function modifyDate(original, options = {}) {
var newDate = new Date(original);
if (Object.prototype.hasOwnProperty.call(options, "year")) {
interface DateTimeSelectProps {
name: string,
disabled: boolean,
disableTime: boolean,
onChange: (date: Date) => void,
value: Date
}

interface ModifyOptions {
year?: number,
month?: number,
date?: number,
time?: string
}

function modifyDate(original: Date, options: ModifyOptions = {}): Date {
const newDate = new Date(original);
if ("year" in options) {
newDate.setFullYear(options.year);
}
if (Object.prototype.hasOwnProperty.call(options, "month")) {
if ("month" in options) {
newDate.setMonth(options.month);
}
if (Object.prototype.hasOwnProperty.call(options, "date")) {
if ("date" in options) {
newDate.setDate(options.date);
}
if (Object.prototype.hasOwnProperty.call(options, "time") &&
if ("time" in options &&
options.time.match(/^[\d]{1,2}(:[\d]{1,2})?$/)) {
newDate.setHours(options.time.split(":")[0]);
newDate.setMinutes(options.time.split(":")[1] || 0);
}
return newDate;
}

function timeToString(time) {
function timeToString(time: Date): string {
return time.toTimeString().slice(0, 5);
}

// Returns an array with years from 2000 to 10 years from now.
function yearOptions() {
let start = 2000;
return Array.apply(null, Array((new Date()).getFullYear() - start + 11))
.map((_, i) => i + start);
function yearOptions(): number[] {
const start = 2000;
const years: number[] = [];
for (let i = start; i <= (new Date()).getFullYear() - start + 11; i++) {
years.push(i);
}
return years;
}

function monthOptions() {
function monthOptions(): string[] {
return(["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"]);
}

function dayOptions() {
return Array.apply(null, Array(31)).map((_, i) => i + 1);
function dayOptions(): number[] {
const numbers: number[] = [];
for (let i = 1; i <= 31; i++) {
numbers.push(i);
}
return numbers;
}

export default function DateTimeSelect(props) {
export default function DateTimeSelect(props: DateTimeSelectProps) {
const { name, disabled, disableTime, onChange, value } = props;

const [timeString, setTimeString] = useState(timeToString(value));
Expand Down Expand Up @@ -90,11 +111,3 @@ export default function DateTimeSelect(props) {
</div>
);
}

DateTimeSelect.propTypes = {
name: PropTypes.string,
disabled: PropTypes.bool,
disableTime: PropTypes.bool,
onChange: PropTypes.func,
value: PropTypes.instanceOf(Date)
};
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import Grid from "./ImageGrid/Grid";

import { ImageRecord, Locale } from "../types";
import { useDragCollection } from "./drag";

function initRecords(props) {
interface ImageGridProps {
attribute: string,
enablePrimary: boolean,
locale: string,
locales: { [index: string]: Locale },
primaryAttribute: string,
records: ImageRecord[],
showEmbed: boolean
}

function initRecords(props: ImageGridProps) {
const primary = props.enablePrimary ?
props.records.filter(r => r.primary).slice(0, 1) :
[];

return [primary, props.records.filter(r => primary.indexOf(r) === -1)];
}

export default function ImageGrid(props) {
export default function ImageGrid(props: ImageGridProps) {
const { attribute, locale, locales, enablePrimary,
primaryAttribute, showEmbed } = props;

Expand All @@ -34,13 +44,3 @@ export default function ImageGrid(props) {
showEmbed={showEmbed} />
);
}

ImageGrid.propTypes = {
attribute: PropTypes.string,
locale: PropTypes.string,
locales: PropTypes.object,
records: PropTypes.array,
enablePrimary: PropTypes.bool,
primaryAttribute: PropTypes.string,
showEmbed: PropTypes.bool
};
Loading

0 comments on commit 123cc42

Please sign in to comment.