Skip to content

Commit 4420d85

Browse files
authored
Merge pull request #74 from admin-golang/infinity-scrolling-template-implementation
{admin,templates}: adds InfinityListPage scaffolding template
2 parents 66de6bb + b0c6536 commit 4420d85

File tree

3 files changed

+232
-0
lines changed

3 files changed

+232
-0
lines changed

admin.go

+46
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const (
5858
EditPage
5959
UploadPage
6060
CardListPage
61+
InfinityListPage
6162
)
6263

6364
type Field struct {
@@ -408,6 +409,49 @@ func NewSideFormPage(p SideFormPageConfig) Pager {
408409
}
409410
}
410411

412+
type IInfinityListPage struct {
413+
page page
414+
415+
Form Form
416+
FooterLabel string
417+
}
418+
419+
func (p *IInfinityListPage) Icon() icon.Icon { return p.page.icon }
420+
func (p *IInfinityListPage) ID() string { return p.page.id }
421+
func (p *IInfinityListPage) IsDefault() bool { return p.page.isDefault }
422+
func (p *IInfinityListPage) ToolbarEnabled() bool { return p.page.toolbarEnabled }
423+
func (p *IInfinityListPage) Type() PageType { return p.page.ttype }
424+
func (p *IInfinityListPage) URL() string { return p.page.url }
425+
func (p *IInfinityListPage) NavTabs() navigation.NavTabs { return p.page.navTabs }
426+
func (p *IInfinityListPage) Navigation() *navigation.Navigation { return p.page.navigation }
427+
func (p *IInfinityListPage) PageHeader() *PageHeader { return p.page.header }
428+
429+
type IInfinityListPageConfig struct {
430+
PageConfig
431+
432+
Form Form
433+
FooterLabel string
434+
}
435+
436+
func NewIInfinityListPage(p IInfinityListPageConfig) Pager {
437+
page := page{
438+
icon: p.Icon,
439+
id: p.ID,
440+
isDefault: p.IsDefault,
441+
toolbarEnabled: p.ToolbarEnabled,
442+
ttype: p.Type,
443+
url: p.URL,
444+
navTabs: p.NavTabs,
445+
header: p.Header,
446+
navigation: p.Navigation,
447+
}
448+
449+
return &IInfinityListPage{
450+
page: page,
451+
Form: p.Form,
452+
}
453+
}
454+
411455
type FFormPage struct {
412456
page page
413457

@@ -613,6 +657,7 @@ func (ad *admin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
613657
FormPage PageType
614658
EditPage PageType
615659
UploadPage PageType
660+
InfinityListPage PageType
616661
RedirectAction state.ActionType
617662
ClearAppStateAction state.ActionType
618663
AccountCircleIcon icon.IconType
@@ -632,6 +677,7 @@ func (ad *admin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
632677
FormPage: FormPage,
633678
EditPage: EditPage,
634679
UploadPage: UploadPage,
680+
InfinityListPage: InfinityListPage,
635681
RedirectAction: state.Redirect,
636682
ClearAppStateAction: state.ClearAppState,
637683
AccountCircleIcon: icon.AccountCircle,

admin_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,47 @@ func newTestAdmin() admin.Admin {
496496
},
497497
},
498498
}),
499+
admin.NewIInfinityListPage(admin.IInfinityListPageConfig{
500+
PageConfig: admin.PageConfig{
501+
IsDefault: true,
502+
ID: "SignIn",
503+
URL: "/sign-in",
504+
Type: admin.InfinityListPage,
505+
Icon: icon.Icon{Type: icon.Inventory},
506+
},
507+
Form: admin.Form{
508+
ID: "signIn",
509+
Title: "Sign in",
510+
Fields: admin.Fields{
511+
admin.Field{
512+
ID: "email",
513+
Type: admin.InputText,
514+
Label: "Email",
515+
IsRequired: true,
516+
Value: "",
517+
FullWidth: true,
518+
},
519+
admin.Field{
520+
ID: "password",
521+
Type: admin.InputPassword,
522+
Label: "Password",
523+
IsRequired: true,
524+
Value: "",
525+
FullWidth: true,
526+
},
527+
},
528+
Submit: admin.Submit{
529+
Label: "Sign In",
530+
URL: "/sign-in",
531+
Method: "POST",
532+
OnSuccess: &admin.OnSubmitSuccess{
533+
RedirectURL: &admin.RedirectURL{
534+
URL: "/dashboard",
535+
},
536+
},
537+
},
538+
},
539+
}),
499540
admin.NewUploadPage(admin.UploadPageConfig{
500541
PageConfig: admin.PageConfig{
501542
ID: "UploadImage",

templates/materialUI.tsx

+145
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,13 @@ function App() {
454454
)}
455455
</AppContext.Consumer>
456456
[[ end ]]
457+
[[ if eq $page.Type $.InfinityListPage ]]
458+
<AppContext.Consumer>
459+
{appState => (
460+
<[[ $page.ID ]]InfinityList appState={appState} handleClearAppState={handleClearAppState} handleSetAppState={handleSetAppState} />
461+
)}
462+
</AppContext.Consumer>
463+
[[ end ]]
457464
</Route>
458465
[[ if $page.IsDefault ]]
459466
<Redirect exact from="/" to="[[ $page.URL ]]" />
@@ -643,6 +650,9 @@ ReactDOM.render(
643650
[[ if eq $page.Type $.UploadPage ]]
644651
[[template "Upload"(WrapPage $.Layout $page $.Pages)]]
645652
[[end]]
653+
[[ if eq $page.Type $.InfinityListPage ]]
654+
[[template "InfinityList"(WrapPage $.Layout $page $.Pages)]]
655+
[[end]]
646656
[[end]]
647657

648658
[[ if and .Layout .Layout.Menu ]]
@@ -1818,6 +1828,141 @@ function [[ .ID ]]Upload({ appState, handleClearAppState, handleSetAppState }) {
18181828
[[ end ]]
18191829
[[end]]
18201830

1831+
[[define "InfinityList"]]
1832+
[[ with .page ]]
1833+
function [[ .ID ]]InfinityList({ handleSetAppState }) {
1834+
const history = useHistory();
1835+
1836+
[[range $field := .Form.Fields]]
1837+
const [ [[$field.ID]], set[[$field.ID]] ] = useState("[[ $field.Value ]]");
1838+
const handle[[$field.ID]]Change = (e) => {
1839+
set[[$field.ID]](e.target.value);
1840+
};
1841+
[[end]]
1842+
1843+
let onSuccessRedirectURL = null;
1844+
[[ if .Form.Submit.OnSuccess ]]
1845+
[[ $redirectURL := Marshal .Form.Submit.OnSuccess.RedirectURL ]]
1846+
const [ getRoute ] = useRouteWithSearchParams();
1847+
onSuccessRedirectURL = getRoute([[ $redirectURL ]]);
1848+
[[ end ]]
1849+
1850+
const handle[[ .Form.ID]]Submit = (e: React.FormEvent<HTMLFormElement>) => {
1851+
e.preventDefault();
1852+
1853+
const payload = {
1854+
[[range $field := .Form.Fields]]
1855+
"[[$field.ID]]": [[$field.ID]],
1856+
[[end]]
1857+
};
1858+
1859+
fetch("[[ .Form.Submit.URL ]]", {
1860+
method: "[[ .Form.Submit.Method ]]",
1861+
body: JSON.stringify(payload),
1862+
})
1863+
.then(async (response) => {
1864+
var data;
1865+
1866+
if (response.headers.get("content-type").includes("application/json")) {
1867+
data = await response.json();
1868+
} else {
1869+
data = await response.text();
1870+
}
1871+
1872+
if (response.ok) {
1873+
[[ if .Form.Submit.OnSuccess ]]
1874+
[[ if .Form.Submit.OnSuccess.SetAppState ]]
1875+
handleSetAppState({ [[ .Form.Submit.OnSuccess.SetAppStateFieldName ]]: data });
1876+
[[ end ]]
1877+
[[ end ]]
1878+
onSuccessRedirectURL && history.push(onSuccessRedirectURL);
1879+
} else {
1880+
setAlertMessage(data);
1881+
setIsSnackbarOpen(true);
1882+
}
1883+
1884+
return data;
1885+
});
1886+
};
1887+
1888+
const [isSnackbarOpen, setIsSnackbarOpen] = useState(false);
1889+
const [alertMessage, setAlertMessage] = useState("");
1890+
const handleSnackbarClose = () => {
1891+
setIsSnackbarOpen(false);
1892+
};
1893+
1894+
return (
1895+
<Grid container component="main" sx={{ height: '100vh' }}>
1896+
<CssBaseline />
1897+
<Snackbar open={isSnackbarOpen} autoHideDuration={6000} onClose={handleSnackbarClose} anchorOrigin={{ vertical: "top", horizontal: "center" }}>
1898+
<Alert onClose={handleSnackbarClose} severity="error">
1899+
{alertMessage}
1900+
</Alert>
1901+
</Snackbar>
1902+
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
1903+
<Box
1904+
sx={{
1905+
my: 8,
1906+
mx: 4,
1907+
display: 'flex',
1908+
flexDirection: 'column',
1909+
alignItems: 'center',
1910+
}}
1911+
>
1912+
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
1913+
[[ if eq .Icon.Type 7 ]]
1914+
<LockOutlinedIcon />
1915+
[[ end ]]
1916+
[[ if eq .Icon.Type 8 ]]
1917+
<EmailIcon />
1918+
[[ end ]]
1919+
</Avatar>
1920+
<Typography component="h1" variant="h5">
1921+
[[ .Form.Title ]]
1922+
</Typography>
1923+
<Box component="form" onSubmit={handle[[ .Form.ID]]Submit} sx={{ mt: 1 }}>
1924+
[[ range $field := .Form.Fields ]]
1925+
[[ if eq $field.Type 0 ]]
1926+
[[ template "PasswordField" (Wrap $field.ID $field.Label $field.IsRequired $field.Value $field.FullWidth $field.IsMultiline $field.NumberOfRows) ]]
1927+
[[ end ]]
1928+
[[ if eq $field.Type 1 ]]
1929+
[[ template "TextField" (Wrap $field.ID $field.Label $field.IsRequired $field.Value $field.FullWidth $field.IsMultiline $field.NumberOfRows) ]]
1930+
[[ end ]]
1931+
[[ end ]]
1932+
{/*<FormControlLabel
1933+
control={<Checkbox value="remember" color="primary" />}
1934+
label="Remember me"
1935+
/>*/}
1936+
<Button
1937+
type="submit"
1938+
fullWidth
1939+
variant="contained"
1940+
sx={{ mt: 3, mb: 2 }}
1941+
>
1942+
[[ .Form.Submit.Label ]]
1943+
</Button>
1944+
<Grid container>
1945+
<Grid item xs>
1946+
{/*<Link href="#" variant="body2">
1947+
Forgot password?
1948+
</Link>*/}
1949+
</Grid>
1950+
<Grid item>
1951+
{/*<Link href="#" variant="body2">
1952+
{"Don't have an account? Sign Up"}
1953+
</Link>*/}
1954+
</Grid>
1955+
</Grid>
1956+
<FooterLabel sx={{ mt: 5 }} label={"[[ .FooterLabel ]]"} />
1957+
</Box>
1958+
</Box>
1959+
</Grid>
1960+
</Grid >
1961+
);
1962+
}
1963+
[[ end ]]
1964+
[[end]]
1965+
18211966
[[define "SideForm"]]
18221967
[[ with .page ]]
18231968
function [[ .ID ]]SideForm({ handleSetAppState }) {

0 commit comments

Comments
 (0)