Skip to content

Commit f370f23

Browse files
committed
Add TypeScript support for React scaffolds
1 parent 8097c2e commit f370f23

File tree

17 files changed

+791
-20
lines changed

17 files changed

+791
-20
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function <%= @action.camelize %>() {
2+
return (
3+
<>
4+
<h1><%= class_name %>#<%= @action %></h1>
5+
<p>Find me in <%= @path %></p>
6+
</>
7+
);
8+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Link, Head } from '@inertiajs/react'
2+
import Form from './Form'
3+
import { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
4+
5+
interface EditProps {
6+
<%= singular_table_name %>: <%= inertia_model_type %>
7+
}
8+
9+
export default function Edit({ <%= singular_table_name %> }: EditProps) {
10+
return (
11+
<>
12+
<Head title="Editing <%= human_name.downcase %>" />
13+
14+
<h1>Editing <%= human_name.downcase %></h1>
15+
16+
<Form
17+
<%= singular_table_name %>={<%= singular_table_name %>}
18+
onSubmit={(form) => {
19+
form.transform((data) => ({ <%= singular_table_name %>: data }))
20+
<% if attributes.any?(&:attachments?) -%>
21+
form.post(`<%= js_resource_path %>`, {
22+
headers: { 'X-HTTP-METHOD-OVERRIDE': 'put' },
23+
})
24+
<% else -%>
25+
form.patch(`<%= js_resource_path %>`)
26+
<% end -%>
27+
}}
28+
submitText="Update <%= human_name.downcase %>"
29+
/>
30+
31+
<br />
32+
33+
<div>
34+
<Link href={`<%= js_resource_path %>`}>Show this <%= human_name.downcase %></Link>
35+
{' | '}
36+
<Link href="<%= js_resources_path %>">Back to <%= human_name.pluralize.downcase %></Link>
37+
</div>
38+
</>
39+
)
40+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { FormEvent } from 'react'
2+
import { useForm, InertiaFormProps } from '@inertiajs/react'
3+
import { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
4+
5+
interface FormProps {
6+
<%= singular_table_name %>: <%= inertia_model_type %>
7+
onSubmit: (form: InertiaFormProps<<%= inertia_component_name %>FormType>) => void
8+
submitText: string
9+
}
10+
11+
type <%= inertia_component_name %>FormType = Omit<<%= inertia_model_type %>, <%= omit_input_attributes.map { |a| "'#{a}'" }.join(' | ') %>><% if custom_form_attributes.any? -%> & {
12+
<% custom_form_attributes.map do |attribute| -%>
13+
<% if attribute.password_digest? -%>
14+
password: string
15+
password_confirmation: string
16+
<% elsif attribute.attachment? -%>
17+
<%= attribute.column_name %>?: File
18+
<% elsif attribute.attachments? -%>
19+
<%= attribute.column_name %>?: File[]
20+
<% end -%>
21+
<% end -%>
22+
}<% end -%>
23+
24+
export default function Form({ <%= singular_table_name %>, onSubmit, submitText }: FormProps) {
25+
const form = useForm<<%= inertia_component_name %>FormType>({
26+
<% attributes.reject { |a| a.attachment? || a.attachments? }.each do |attribute| -%>
27+
<% if attribute.password_digest? -%>
28+
password: '',
29+
password_confirmation: '',
30+
<% else -%>
31+
<%= attribute.column_name %>: <%= singular_table_name %>.<%= attribute.column_name %>,
32+
<% end -%>
33+
<% end -%>
34+
})
35+
const { data, setData, errors, processing } = form
36+
37+
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
38+
e.preventDefault()
39+
onSubmit(form)
40+
}
41+
42+
return (
43+
<form onSubmit={handleSubmit}>
44+
<% attributes.each do |attribute| -%>
45+
<% if attribute.password_digest? -%>
46+
<div>
47+
<label style={{ display: 'block' }} htmlFor="password">
48+
Password
49+
</label>
50+
<input
51+
type="password"
52+
name="password"
53+
id="password"
54+
onChange={(e) => setData('password', e.target.value)}
55+
/>
56+
{errors.password && (
57+
<div style={{ color: 'red' }}>{errors.password}</div>
58+
)}
59+
</div>
60+
61+
<div>
62+
<label style={{ display: 'block' }} htmlFor="password_confirmation">
63+
Password Confirmation
64+
</label>
65+
<input
66+
type="password"
67+
name="password_confirmation"
68+
id="password_confirmation"
69+
onChange={(e) => setData('password_confirmation', e.target.value)}
70+
/>
71+
{errors.password_confirmation && (
72+
<div style={{ color: 'red' }}>{errors.password_confirmation}</div>
73+
)}
74+
</div>
75+
<% else -%>
76+
<div>
77+
<label style={{ display: 'block' }} htmlFor="<%= attribute.singular_name %>">
78+
<%= attribute.human_name %>
79+
</label>
80+
<% if input_type(attribute) == "text_area" -%>
81+
<textarea
82+
name="<%= attribute.singular_name %>"
83+
id="<%= attribute.singular_name %>"
84+
value={data.<%= attribute.column_name %>}
85+
onChange={(e) => setData('<%= attribute.column_name %>', e.target.value)}
86+
/>
87+
<% elsif attribute.attachment? -%>
88+
<input
89+
type="file"
90+
name="<%= attribute.singular_name %>"
91+
id="<%= attribute.singular_name %>"
92+
onChange={(e) => setData('<%= attribute.column_name %>', (e.target.files || [])[0])}
93+
/>
94+
<% elsif attribute.attachments? -%>
95+
<input
96+
type="file"
97+
multiple
98+
name="<%= attribute.singular_name %>[]"
99+
id="<%= attribute.singular_name %>"
100+
onChange={(e) => setData('<%= attribute.column_name %>', Array.from(e.target.files || []))}
101+
/>
102+
<% elsif input_type(attribute) == "checkbox" -%>
103+
<input
104+
type="<%= input_type(attribute) %>"
105+
name="<%= attribute.singular_name %>"
106+
id="<%= attribute.singular_name %>"
107+
checked={data.<%= attribute.column_name %>}
108+
onChange={(e) => setData('<%= attribute.column_name %>', e.target.checked)}
109+
/>
110+
<% elsif input_type(attribute) == "number" -%>
111+
<input
112+
type="<%= input_type(attribute) %>"
113+
name="<%= attribute.singular_name %>"
114+
id="<%= attribute.singular_name %>"
115+
value={data.<%= attribute.column_name %>}
116+
onChange={(e) => setData('<%= attribute.column_name %>', parseInt(e.target.value))}
117+
/>
118+
<% else -%>
119+
<input
120+
type="<%= input_type(attribute) %>"
121+
name="<%= attribute.singular_name %>"
122+
id="<%= attribute.singular_name %>"
123+
value={data.<%= attribute.column_name %>}
124+
onChange={(e) => setData('<%= attribute.column_name %>', e.target.value)}
125+
/>
126+
<% end -%>
127+
{errors.<%= attribute.column_name %> && (
128+
<div style={{ color: 'red' }}>{errors.<%= attribute.column_name %>}</div>
129+
)}
130+
</div>
131+
<% end -%>
132+
<% end -%>
133+
<div>
134+
<button type="submit" disabled={processing}>
135+
{submitText}
136+
</button>
137+
</div>
138+
</form>
139+
)
140+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Link, Head } from '@inertiajs/react'
2+
import <%= inertia_component_name %>, { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
3+
4+
interface IndexProps {
5+
<%= plural_table_name %>: <%= inertia_model_type %>[]
6+
flash: { notice: string }
7+
}
8+
9+
export default function Index({ <%= plural_table_name %>, flash }: IndexProps) {
10+
return (
11+
<>
12+
<Head title="<%= human_name.pluralize %>" />
13+
14+
{flash.notice && <p style={{ color: 'green' }}>{flash.notice}</p>}
15+
16+
<h1><%= human_name.pluralize %></h1>
17+
<div>
18+
{<%= plural_table_name %>.map((<%= singular_table_name %>) => (
19+
<div key={<%= singular_table_name %>.id}>
20+
<<%= inertia_component_name %> <%= singular_table_name %>={<%= singular_table_name %>} />
21+
<p>
22+
<Link href={`<%= js_resource_path %>`}>Show this <%= human_name.downcase %></Link>
23+
</p>
24+
</div>
25+
))}
26+
</div>
27+
28+
<Link href="<%= js_new_resource_path %>">New <%= human_name.downcase %></Link>
29+
</>
30+
)
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Link, Head } from '@inertiajs/react'
2+
import Form from './Form'
3+
import { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
4+
5+
interface NewProps {
6+
<%= singular_table_name %>: <%= inertia_model_type %>
7+
}
8+
9+
export default function New({ <%= singular_table_name %> }: NewProps) {
10+
return (
11+
<>
12+
<Head title="New <%= human_name.downcase %>" />
13+
14+
<h1>New <%= human_name.downcase %></h1>
15+
16+
<Form
17+
<%= singular_table_name %>={<%= singular_table_name %>}
18+
onSubmit={(form) => {
19+
form.transform((data) => ({ <%= singular_table_name %>: data }))
20+
form.post('<%= js_resources_path %>')
21+
}}
22+
submitText="Create <%= human_name.downcase %>"
23+
/>
24+
25+
<br />
26+
27+
<div>
28+
<Link href="<%= js_resources_path %>">Back to <%= human_name.pluralize.downcase %></Link>
29+
</div>
30+
</>
31+
)
32+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
export interface <%= inertia_model_type %> {
2+
id: number
3+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
4+
<%= attribute.column_name %>: <%= ts_type(attribute) %>
5+
<% end -%>
6+
}
7+
8+
interface <%= inertia_component_name %>Props {
9+
<%= singular_table_name %>: <%= inertia_model_type %>
10+
}
11+
12+
export default function <%= inertia_component_name %>({ <%= singular_table_name %> }: <%= inertia_component_name %>Props) {
13+
return (
14+
<div>
15+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
16+
<p>
17+
<strong><%= attribute.human_name %>:</strong>
18+
<% if attribute.attachment? -%>
19+
{<%= singular_table_name %>.<%= attribute.column_name %> && (
20+
<a href={<%= singular_table_name %>.<%= attribute.column_name %>.url}>{<%= singular_table_name %>.<%= attribute.column_name %>.filename}</a>
21+
)}
22+
</p>
23+
<% elsif attribute.attachments? -%>
24+
</p>
25+
{<%= singular_table_name %>.<%= attribute.column_name %>.map((file, i) => (
26+
<div key={i}>
27+
<a href={file.url}>{file.filename}</a>
28+
</div>
29+
))}
30+
<% else -%>
31+
{<%= singular_table_name %>.<%= attribute.column_name %>.toString()}
32+
</p>
33+
<% end -%>
34+
<% end -%>
35+
</div>
36+
)
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { MouseEvent } from 'react'
2+
import { Link, Head } from '@inertiajs/react'
3+
import <%= inertia_component_name %>, { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
4+
5+
interface ShowProps {
6+
<%= singular_table_name %>: <%= inertia_model_type %>
7+
flash: { notice: string }
8+
}
9+
10+
export default function Show({ <%= singular_table_name %>, flash }: ShowProps) {
11+
const onDestroy = (e: MouseEvent) => {
12+
if (!confirm('Are you sure you want to delete this <%= human_name.downcase %>?')) {
13+
e.preventDefault()
14+
}
15+
}
16+
17+
return (
18+
<>
19+
<Head title={`<%= human_name %> #${<%= singular_table_name %>.id}`} />
20+
21+
{flash.notice && <p style={{ color: 'green' }}>{flash.notice}</p>}
22+
23+
<h1><%= human_name %> #{<%= singular_table_name %>.id}</h1>
24+
25+
<<%= inertia_component_name %> <%= singular_table_name %>={<%= singular_table_name %>} />
26+
27+
<div>
28+
<Link href={`<%= js_edit_resource_path %>`}>Edit this <%= human_name.downcase %></Link>
29+
{' | '}
30+
<Link href="<%= js_resources_path %>">Back to <%= human_name.pluralize.downcase %></Link>
31+
32+
<br />
33+
34+
<Link
35+
href={`<%= js_resource_path %>`}
36+
onClick={onDestroy}
37+
as="button"
38+
method="delete"
39+
>
40+
Destroy this <%= human_name.downcase %>
41+
</Link>
42+
</div>
43+
</>
44+
)
45+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function <%= @action.camelize %>() {
2+
return (
3+
<>
4+
<h1 className="font-bold text-4xl"><%= class_name %>#<%= @action %></h1>
5+
<p>Find me in <%= @path %></p>
6+
</>
7+
);
8+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Link, Head } from '@inertiajs/react'
2+
import Form from './Form'
3+
import { <%= inertia_model_type %> } from './<%= inertia_component_name %>'
4+
5+
interface EditProps {
6+
<%= singular_table_name %>: <%= inertia_model_type %>
7+
}
8+
9+
export default function Edit({ <%= singular_table_name %> }: EditProps) {
10+
return (
11+
<>
12+
<Head title="Editing <%= human_name.downcase %>" />
13+
14+
<div className="mx-auto md:w-2/3 w-full px-8 pt-8">
15+
<h1 className="font-bold text-4xl">Editing <%= human_name.downcase %></h1>
16+
17+
<Form
18+
<%= singular_table_name %>={<%= singular_table_name %>}
19+
onSubmit={(form) => {
20+
form.transform((data) => ({ <%= singular_table_name %>: data }))
21+
<% if attributes.any?(&:attachments?) -%>
22+
form.post(`<%= js_resource_path %>`, {
23+
headers: { 'X-HTTP-METHOD-OVERRIDE': 'put' },
24+
})
25+
<% else -%>
26+
form.patch(`<%= js_resource_path %>`)
27+
<% end -%>
28+
}}
29+
submitText="Update <%= human_name.downcase %>"
30+
/>
31+
32+
<Link
33+
href={`<%= js_resource_path %>`}
34+
className="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
35+
>
36+
Show this <%= human_name.downcase %>
37+
</Link>
38+
<Link
39+
href="<%= js_resources_path %>"
40+
className="ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium"
41+
>
42+
Back to <%= human_name.pluralize.downcase %>
43+
</Link>
44+
</div>
45+
</>
46+
)
47+
}

0 commit comments

Comments
 (0)