-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add linktree (admin, router, conteroller)
- Loading branch information
Showing
17 changed files
with
365 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { Box, Button, DrawerContent, DrawerFooter, Icon } from "@adminjs/design-system"; | ||
import { | ||
ActionProps, | ||
BasePropertyComponent, | ||
RecordJSON, | ||
useCurrentAdmin, | ||
useRecord, | ||
useTranslation | ||
} from "adminjs"; | ||
import React, { FC, useEffect } from "react"; | ||
import { useNavigate } from "react-router"; | ||
|
||
const appendForceRefresh = (url: string, search?: string): string => { | ||
const searchParamsIdx = url.lastIndexOf("?"); | ||
const urlSearchParams = searchParamsIdx !== -1 ? url.substring(searchParamsIdx + 1) : null; | ||
|
||
const oldParams = new URLSearchParams(search ?? urlSearchParams ?? window.location.search ?? ""); | ||
const shouldIgnoreOldParams = new URLSearchParams(urlSearchParams || "").get("ignore_params") === "true"; | ||
const newParams = shouldIgnoreOldParams ? new URLSearchParams("") : new URLSearchParams(oldParams.toString()); | ||
|
||
newParams.set("refresh", "true"); | ||
|
||
const newUrl = searchParamsIdx !== -1 ? url.substring(0, searchParamsIdx) : url; | ||
|
||
return `${newUrl}?${newParams.toString()}`; | ||
}; | ||
|
||
const Edit: FC<ActionProps> = (props) => { | ||
const { record: initialRecord, resource, action } = props; | ||
const [currentAdmin, setCurrentAdmin] = useCurrentAdmin(); | ||
const {role} = currentAdmin as any | ||
const { record, handleChange, submit: handleSubmit, loading, setRecord } = useRecord(initialRecord, resource.id); | ||
const { translateButton } = useTranslation(); | ||
const navigate = useNavigate(); | ||
const getActionElementCss = (resourceId: string, actionName: string, suffix: string) => `${resourceId}-${actionName}-${suffix}` | ||
// const value = record.params?.[property.path] | ||
// const error = record.errors && record.errors[property.path] | ||
// console.log(props) | ||
useEffect(() => { | ||
if (initialRecord) { | ||
setRecord(initialRecord); | ||
} | ||
}, [initialRecord]); | ||
const majorProp = resource.editProperties.find(p => p.name == 'major'); | ||
if (majorProp && majorProp.availableValues) { | ||
majorProp.availableValues = majorProp.availableValues.filter(p => p.label == role) | ||
} | ||
console.log(resource.editProperties, {majorProp}); | ||
const submit = (event: React.FormEvent<HTMLFormElement>): boolean => { | ||
event.preventDefault(); | ||
handleSubmit().then((response) => { | ||
if (response.data.redirectUrl) { | ||
navigate(appendForceRefresh(response.data.redirectUrl)); | ||
} | ||
}); | ||
return false; | ||
}; | ||
|
||
const contentTag = getActionElementCss(resource.id, action.name, "drawer-content"); | ||
const formTag = getActionElementCss(resource.id, action.name, "form"); | ||
const footerTag = getActionElementCss(resource.id, action.name, "drawer-footer"); | ||
const buttonTag = getActionElementCss(resource.id, action.name, "drawer-submit"); | ||
return ( | ||
<Box as="form" onSubmit={submit} flex flexDirection="column" data-css={formTag}> | ||
<DrawerContent data-css={contentTag}> | ||
{resource.editProperties.map((property) => ( | ||
<BasePropertyComponent | ||
key={property.propertyPath} | ||
where="edit" | ||
onChange={handleChange} | ||
property={property} | ||
resource={resource} | ||
record={record as RecordJSON} | ||
/> | ||
))} | ||
</DrawerContent> | ||
<DrawerFooter data-css={footerTag}> | ||
<Button variant="contained" type="submit" data-css={buttonTag} data-testid="button-save" disabled={loading}> | ||
{loading ? <Icon icon="Loader" spin /> : null} | ||
{translateButton("save", resource.id)} | ||
</Button> | ||
</DrawerFooter> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default Edit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { ActionHandler, Filter, SortSetter, flat, populator } from "adminjs"; | ||
|
||
const list: ActionHandler<any> = async (request, response, context) => { | ||
const { query } = request; // 요청 url의 query 부분 추출 | ||
// console.log(query); | ||
|
||
const { resource, _admin, currentAdmin } = context; // db table | ||
const { role } = currentAdmin; | ||
const unflattenQuery = flat.unflatten( | ||
query || {} | ||
); | ||
let { page, perPage } = unflattenQuery; | ||
// 진행중인 행사 탭에서는 시작일 내림차순 정렬 | ||
// 종료된 행사 탭에서는 종료일 내림차순 정렬 | ||
const { | ||
sortBy = "order", | ||
direction = "asc", | ||
filters = { major: role }, | ||
} = unflattenQuery; | ||
|
||
// adminOptions.settings.defaultPerPage, 한 페이지에 몇 행 보여줄 지 | ||
if (perPage) { | ||
perPage = +perPage > 500 ? 500 : +perPage; | ||
} else { | ||
perPage = _admin.options.settings?.defaultPerPage ?? 10; | ||
} | ||
page = +page || 1; | ||
|
||
// resource(DB table)에서 어떤 데이터를 가져올 지 filter 생성 | ||
const listProperties = resource.decorate().getListProperties(); | ||
const firstProperty = listProperties.find((p) => p.isSortable()); | ||
let sort; | ||
if (firstProperty) { | ||
sort = SortSetter( | ||
{ sortBy, direction }, | ||
firstProperty.name(), | ||
resource.decorate().options | ||
); | ||
} | ||
const filter = await new Filter( | ||
{ ...filters }, | ||
resource | ||
).populate(context); | ||
const records = await resource.find( | ||
filter, | ||
{ | ||
limit: perPage, | ||
offset: (page - 1) * perPage, | ||
sort, | ||
}, | ||
context | ||
); | ||
|
||
const populatedRecords = await populator(records, context); | ||
context.records = populatedRecords; | ||
|
||
// 메타데이터 및 가져온 데이터 return | ||
const total = await resource.count(filter, context); | ||
return { | ||
meta: { | ||
total, | ||
perPage, | ||
page, | ||
direction: sort?.direction, | ||
sortBy: sort?.sortBy, | ||
}, | ||
records: populatedRecords.map((r) => r.toJSON(currentAdmin)), | ||
}; | ||
}; | ||
|
||
export const LinktreeHandler = { | ||
list, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { ResourceOptions } from "adminjs"; | ||
import { linktreeTab } from "./common.js"; | ||
import { Components } from "../components/index.js"; | ||
import { LinktreeHandler } from "../handlers/linktree.js"; | ||
|
||
const linktreeOptions: ResourceOptions = { | ||
navigation: linktreeTab, | ||
|
||
listProperties: ["order", "text", "src"], | ||
showProperties: ["major", "text", "src", "order"], | ||
editProperties: ["major", "text", "src", "order"], | ||
filterProperties: ["major", "text", "src", "order"], | ||
|
||
properties: { | ||
content: { | ||
type: "richtext", | ||
}, | ||
major_advisor: { | ||
isRequired: true, | ||
}, | ||
image: { | ||
isArray: true, | ||
}, | ||
}, | ||
actions: { | ||
new: { | ||
component: Components.linktree_edit, | ||
}, | ||
edit: { | ||
component: Components.linktree_edit, | ||
}, | ||
list: { | ||
handler: LinktreeHandler.list | ||
} | ||
} | ||
}; | ||
|
||
export const LINKTREE = { | ||
options: linktreeOptions, | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { getLinktrees } from "./linktree.js"; | ||
|
||
export { | ||
getLinktrees | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { NextFunction, Request, Response } from "express"; | ||
import { redisGetAndParse } from "../common_method/utils.js"; | ||
|
||
// GET /events | ||
export const getLinktrees = async ( | ||
req: Request<any, any>, | ||
res: Response, | ||
next: NextFunction | ||
) => { | ||
try { | ||
const major = req.params.major_advisor; | ||
if (!major) throw new Error('올바르지 않은 학과') | ||
const linktrees = await redisGetAndParse(`linktrees:${major}`); | ||
return res.status(200).json(linktrees); | ||
} catch (error) { | ||
console.error(error); | ||
res.status(500).json({ error: error.message }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { DataTypes, Model } from 'sequelize'; | ||
import { sequelize } from './sequelize.js'; | ||
|
||
interface LinktreeAttributes { | ||
id: number; | ||
src: string; | ||
text: string; | ||
major: '컴퓨터' | '소프트'; | ||
order: number; | ||
} | ||
|
||
class Linktree extends Model<LinktreeAttributes> implements LinktreeAttributes { | ||
public id!: number; | ||
public src!: string; | ||
public text!: string; | ||
public major!: '컴퓨터' | '소프트'; | ||
public order!: number; | ||
} | ||
|
||
Linktree.init( | ||
{ | ||
id: { | ||
type: DataTypes.INTEGER.UNSIGNED, | ||
primaryKey: true, | ||
autoIncrement: true, | ||
allowNull: false, | ||
}, | ||
src: { | ||
type: DataTypes.STRING(200), | ||
allowNull: false, | ||
}, | ||
text: { | ||
type: DataTypes.STRING(100), | ||
allowNull: false, | ||
}, | ||
major: { | ||
type: DataTypes.ENUM('컴퓨터', '소프트'), | ||
allowNull: false, | ||
}, | ||
order: { | ||
type: DataTypes.INTEGER({unsigned: true}), | ||
allowNull: false | ||
} | ||
}, | ||
{ | ||
sequelize, | ||
modelName: 'Linktree', | ||
tableName: 'linktrees', | ||
timestamps: false, | ||
} | ||
); | ||
|
||
export default Linktree; |
Oops, something went wrong.