Skip to content

Commit e7df392

Browse files
committed
feat(layout): add branch fetching and display in repo info
1 parent 674acef commit e7df392

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

Diff for: src/app/(default)/r/[owner]/[repo]/post/layout.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use client'
2+
3+
4+
import React from "react";
5+
import {IoMdClose} from "react-icons/io";
6+
7+
export default function PostRepoLayout(props: { children: React.ReactNode }) {
8+
return (
9+
<div>
10+
<div className="back" onClick={() => window.history.back()}>
11+
<IoMdClose/>
12+
<span>返回</span>
13+
</div>
14+
{props.children}
15+
</div>
16+
)
17+
}

Diff for: src/app/(default)/r/[owner]/[repo]/post/page.tsx

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
'use client'
2+
3+
import {useEffect, useState} from "react";
4+
import usePageContext from "@/store/usePageContext";
5+
import {Form, useForm} from "@mantine/form";
6+
import {CommitModel, DataProductPostParam} from "@/server/types";
7+
import {RepoApi} from "@/server/RepoApi";
8+
import {AppWrite} from "@/server/Client";
9+
import {Box, Button, Divider, Input, InputLabel, LoadingOverlay, Select} from "@mantine/core";
10+
import {notifications} from "@mantine/notifications";
11+
import {ProductApi} from "@/server/ProductApi";
12+
13+
export default function ProductPostPage(){
14+
const context = usePageContext();
15+
const [Parma,setParma] = useState<{ owner: string, repo: string } | undefined>();
16+
const [Heads, setHeads] = useState<CommitModel[]>([]);
17+
const [Publishing, setPublishing] = useState(false);
18+
const repo_api = new RepoApi();
19+
const product_api = new ProductApi();
20+
useEffect(() => {
21+
if (context.repoCtx){
22+
const {owner, repoName} = context.repoCtx;
23+
setParma({owner,repo: repoName})
24+
for(const idx in context.repoCtx.branches) {
25+
const branch = context.repoCtx.branches[idx];
26+
repo_api.OneCommit(owner,repoName, branch.name, branch.head)
27+
.then((res) => {
28+
if (res.status === 200) {
29+
const json:AppWrite<CommitModel> = JSON.parse(res.data);
30+
if (json.code === 200 && json.data) {
31+
setHeads((prev) => {
32+
if (prev.find((item) => item.id === json.data!.id)) {
33+
return prev;
34+
}else {
35+
return [...prev, json.data!];
36+
}
37+
});
38+
}
39+
}
40+
})
41+
}
42+
}
43+
}, []);
44+
const form = useForm({
45+
mode: "uncontrolled",
46+
initialValues: {
47+
name: '',
48+
description: '',
49+
license: '',
50+
price: 0,
51+
hash: '',
52+
type: '',
53+
},
54+
validate: {
55+
name: (value) => {
56+
if (!value) {
57+
return "Name is required";
58+
}
59+
if (value.length > 100) {
60+
return "Name is too long";
61+
}
62+
if (value.includes("/")) {
63+
return "Name is invalid";
64+
}
65+
return null;
66+
},
67+
license: (value) => {
68+
if (!value) {
69+
return "License is required";
70+
}
71+
return null;
72+
},
73+
hash: (value) => {
74+
if (!value) {
75+
return "Hash is required";
76+
}
77+
return null;
78+
},
79+
type: (value) => {
80+
if (!value) {
81+
return "Type is required";
82+
}
83+
return null;
84+
},
85+
price: (value) => {
86+
if (!value) {
87+
return "Price is required";
88+
}
89+
if (value < 0){
90+
return "Price is invalid, it is eqt 0";
91+
}
92+
},
93+
}
94+
});
95+
const onSubmit = () => {
96+
if (Publishing) return;
97+
setPublishing(true);
98+
form.validate();
99+
if (!form.isValid()){
100+
notifications
101+
.show({
102+
message: "Please fill in all required fields",
103+
color: "red",
104+
})
105+
setPublishing(false)
106+
return;
107+
}
108+
const param:DataProductPostParam = {
109+
name: form.getValues().name,
110+
description: form.getValues().description,
111+
license: form.getValues().license,
112+
price: form.getValues().price,
113+
hash: form.getValues().hash,
114+
type: form.getValues().type,
115+
}
116+
product_api.Post(Parma!.owner, Parma!.repo, param)
117+
.then((res) => {
118+
if (res.status === 200) {
119+
const json:AppWrite<string> = JSON.parse(res.data);
120+
if (json.code === 200 && json.data) {
121+
notifications.show({
122+
title: "Success",
123+
message: "Post success"
124+
})
125+
setTimeout(() => {
126+
window.location.href = "/r/" + Parma!.owner + "/" + Parma!.repo;
127+
}, 1000);
128+
}
129+
}
130+
})
131+
132+
setPublishing(false);
133+
134+
}
135+
136+
return (
137+
<div className="post">
138+
<h1>
139+
POST
140+
</h1>
141+
<Box pos="relative">
142+
<LoadingOverlay visible={Publishing} loaderProps={{ children: 'Forking...' }} />
143+
<Form
144+
form={form}
145+
id="LayoutModelRepositoryPOST"
146+
>
147+
<Select
148+
name={"hash"}
149+
label="hash"
150+
title="Select hash"
151+
withAsterisk
152+
key={form.key("hash")}
153+
data={
154+
Heads.map((item) => {
155+
return {
156+
value: item.id,
157+
label: item.id + " " + item.message + " " + item.author + " " + new Date(item.time * 1000).toISOString()
158+
}
159+
})
160+
}
161+
{...form.getInputProps("owner")}
162+
/>
163+
<InputLabel className="w-full">
164+
name<a style={{color: 'red'}}> *</a>
165+
<Input
166+
name="name"
167+
placeholder="Enter product name"
168+
type="tel"
169+
aria-autocomplete={"none"}
170+
key={form.key("name")}
171+
{...form.getInputProps("name")}
172+
/>
173+
</InputLabel>
174+
175+
<InputLabel className="w-full">
176+
description(optional)
177+
<Input
178+
name="description"
179+
placeholder="Enter product descrition"
180+
type="tel"
181+
aria-autocomplete={"none"}
182+
key={form.key("description")}
183+
{...form.getInputProps("description")}
184+
/>
185+
</InputLabel>
186+
187+
<InputLabel className="w-full">
188+
license<a style={{color: 'red'}}> *</a>
189+
<Input
190+
name="license"
191+
placeholder="Enter product license"
192+
type="tel"
193+
aria-autocomplete={"none"}
194+
key={form.key("license")}
195+
{...form.getInputProps("license")}
196+
/>
197+
</InputLabel>
198+
<InputLabel className="w-full">
199+
price<a style={{color: 'red'}}> *</a>
200+
<Input
201+
name="price"
202+
placeholder="Enter product price"
203+
type="number"
204+
aria-autocomplete={"none"}
205+
key={form.key("price")}
206+
{...form.getInputProps("price")}
207+
/>
208+
</InputLabel>
209+
<InputLabel className="w-full">
210+
type<a style={{color: 'red'}}> *</a>
211+
<Input
212+
name="type"
213+
placeholder="Enter product type"
214+
type="tel"
215+
aria-autocomplete={"none"}
216+
key={form.key("type")}
217+
{...form.getInputProps("type")}
218+
/>
219+
</InputLabel>
220+
<Divider/>
221+
<div style={{
222+
display: "flex",
223+
justifyContent: "flex-end",
224+
alignItems: "center",
225+
gap: "1rem",
226+
marginRight: "auto"
227+
}}>
228+
<Button color="green" type="submit" onClick={onSubmit}>
229+
Publish
230+
</Button>
231+
</div>
232+
</Form>
233+
</Box>
234+
</div>
235+
)
236+
237+
}

0 commit comments

Comments
 (0)