Skip to content

Commit edb45d4

Browse files
CopilotTechQuery
andcommitted
Refactor sponsor management to cooperation management with backend alignment
Co-authored-by: TechQuery <19969570+TechQuery@users.noreply.github.com>
1 parent 9464c2e commit edb45d4

20 files changed

Lines changed: 515 additions & 398 deletions

File tree

components/Activity/menu.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import { MenuItem } from '../User/SessionBox';
44
export const organizerMenu = ({ t }: typeof i18n, activityId: number): MenuItem[] => [
55
{ href: `/activity/${activityId}/editor`, title: t('edit_activity') },
66
{ href: `/activity/${activityId}/forum`, title: t('forum_list') },
7-
{ href: `/activity/${activityId}/sponsor`, title: t('sponsor_management') },
7+
{ href: `/activity/${activityId}/cooperation`, title: t('cooperation_management') },
88
];

components/Cooperation/Editor.tsx

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { Activity, Cooperation, Tag } from '@open-source-bazaar/activityhub-service';
2+
import { computed } from 'mobx';
3+
import { observer } from 'mobx-react';
4+
import { ObservedComponent } from 'mobx-react-helper';
5+
import { Field, RestForm } from 'mobx-restful-table';
6+
7+
import { CooperationModel } from '../../models/Cooperation';
8+
import fileStore from '../../models/File';
9+
import { OrganizationModel } from '../../models/Organization';
10+
import { i18n, I18nContext } from '../../models/Translation';
11+
import { renderTagInput } from '../Tag';
12+
13+
export interface CooperationEditorProps {
14+
cooperation?: Cooperation;
15+
activityId: number;
16+
activity?: Activity;
17+
}
18+
19+
@observer
20+
export class CooperationEditor extends ObservedComponent<CooperationEditorProps, typeof i18n> {
21+
static contextType = I18nContext;
22+
23+
cooperationStore = new CooperationModel(this.props.activityId);
24+
organizationStore = new OrganizationModel();
25+
fileStore = fileStore;
26+
27+
componentDidMount() {
28+
const { cooperation } = this.props;
29+
30+
if (cooperation) this.cooperationStore.currentOne = cooperation;
31+
}
32+
33+
submitHandler = () => {
34+
const { activityId, cooperation } = this.props;
35+
const { t } = this.observedContext;
36+
37+
alert(cooperation ? t('cooperation_updated_successfully') : t('cooperation_created_successfully'));
38+
39+
window.location.href = `/activity/${activityId}/cooperation`;
40+
};
41+
42+
@computed
43+
get fields(): Field<Cooperation>[] {
44+
const { t } = this.observedContext;
45+
const { activity } = this.props;
46+
47+
return [
48+
{
49+
key: 'partner',
50+
renderLabel: t('organization'),
51+
renderInput: renderTagInput(this.organizationStore),
52+
required: true,
53+
invalidMessage: t('field_required'),
54+
},
55+
{
56+
key: 'level',
57+
renderLabel: t('cooperation_level'),
58+
type: 'select',
59+
options: activity?.cooperationLevels?.map((level: Tag) => ({
60+
title: level.name,
61+
value: String(level.id),
62+
})) || [],
63+
required: true,
64+
invalidMessage: t('field_required'),
65+
},
66+
];
67+
}
68+
69+
render() {
70+
const { downloading, uploading } = this.cooperationStore;
71+
72+
const loading = downloading > 0 || uploading > 0;
73+
74+
return (
75+
<>
76+
<RestForm
77+
className="container-fluid"
78+
translator={this.observedContext}
79+
store={this.cooperationStore}
80+
fields={this.fields}
81+
onSubmit={this.submitHandler}
82+
/>
83+
{loading && <div>Loading...</div>}
84+
</>
85+
);
86+
}
87+
}

components/Cooperation/List.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Cooperation } from '@open-source-bazaar/activityhub-service';
2+
import { computed } from 'mobx';
3+
import { observer } from 'mobx-react';
4+
import { ObservedComponent } from 'mobx-react-helper';
5+
import { Column, RestTable } from 'mobx-restful-table';
6+
import { Container } from 'react-bootstrap';
7+
8+
import { CooperationModel } from '../../models/Cooperation';
9+
import { i18n, I18nContext } from '../../models/Translation';
10+
import { PageHead } from '../Navigator/PageHead';
11+
12+
export interface CooperationListProps {
13+
activityId: number;
14+
}
15+
16+
@observer
17+
export class CooperationList extends ObservedComponent<CooperationListProps, typeof i18n> {
18+
static contextType = I18nContext;
19+
20+
cooperationStore = new CooperationModel(this.props.activityId);
21+
22+
@computed
23+
get columns(): Column<Cooperation>[] {
24+
const { t } = this.observedContext,
25+
{ activityId } = this.observedProps;
26+
27+
return [
28+
{
29+
key: 'partner',
30+
renderHead: t('organization'),
31+
renderBody: ({ id, partner }) => (
32+
<a href={`/activity/${activityId}/cooperation/${id}/editor`}>
33+
{partner?.name || t('unknown')}
34+
</a>
35+
),
36+
required: true,
37+
invalidMessage: t('field_required'),
38+
},
39+
{
40+
key: 'level',
41+
renderHead: t('cooperation_level'),
42+
renderBody: ({ level }) => level?.name || t('unknown'),
43+
},
44+
];
45+
}
46+
47+
render() {
48+
const { t } = this.observedContext;
49+
50+
return (
51+
<Container fluid>
52+
<PageHead title={t('cooperation_management')} />
53+
54+
<RestTable
55+
className="h-100 text-center"
56+
striped
57+
hover
58+
editable
59+
deletable
60+
columns={this.columns}
61+
store={this.cooperationStore}
62+
translator={this.observedContext}
63+
/>
64+
</Container>
65+
);
66+
}
67+
}

components/Navigator/MainNavigator.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export const MainNavigator: FC = observer(() => {
2323
<Nav className="me-auto">
2424
<Nav.Link href="/article">{t('article')}</Nav.Link>
2525

26+
<Nav.Link href="/organization">{t('organization_list')}</Nav.Link>
27+
2628
<Nav.Link href="/component">{t('component')}</Nav.Link>
2729

2830
<Nav.Link href="/pagination">{t('pagination')}</Nav.Link>

components/Organization/SponsorCard.tsx renamed to components/Organization/CooperationCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
33
import { FC } from 'react';
44
import { Image } from 'react-bootstrap';
55

6-
export const SponsorCard: FC<Organization> = observer(({ name, url, logo }) => (
6+
export const CooperationCard: FC<Organization> = observer(({ name, url, logo }) => (
77
<a
88
href={url}
99
target="_blank"

components/Organization/Editor.tsx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Organization } from '@open-source-bazaar/activityhub-service';
2+
import { computed } from 'mobx';
3+
import { observer } from 'mobx-react';
4+
import { ObservedComponent } from 'mobx-react-helper';
5+
import { Field, RestForm } from 'mobx-restful-table';
6+
7+
import fileStore from '../../models/File';
8+
import organizationStore from '../../models/Organization';
9+
import { i18n, I18nContext } from '../../models/Translation';
10+
11+
export interface OrganizationEditorProps {
12+
organization?: Organization;
13+
}
14+
15+
@observer
16+
export class OrganizationEditor extends ObservedComponent<OrganizationEditorProps, typeof i18n> {
17+
static contextType = I18nContext;
18+
19+
fileStore = fileStore;
20+
21+
componentDidMount() {
22+
const { organization } = this.props;
23+
24+
if (organization) organizationStore.currentOne = organization;
25+
}
26+
27+
submitHandler = () => {
28+
const { organization } = this.props;
29+
const { t } = this.observedContext;
30+
31+
alert(organization ? t('organization_updated_successfully') : t('organization_created_successfully'));
32+
33+
window.location.href = `/organization`;
34+
};
35+
36+
@computed
37+
get fields(): Field<Organization>[] {
38+
const { t } = this.observedContext;
39+
40+
return [
41+
{
42+
key: 'name',
43+
renderLabel: t('name'),
44+
required: true,
45+
invalidMessage: t('field_required'),
46+
},
47+
{
48+
key: 'englishName',
49+
renderLabel: t('english_name'),
50+
},
51+
{
52+
key: 'url',
53+
renderLabel: t('website'),
54+
type: 'url',
55+
},
56+
{
57+
key: 'logo',
58+
renderLabel: t('logo'),
59+
type: 'file',
60+
accept: 'image/*',
61+
uploader: this.fileStore,
62+
},
63+
{
64+
key: 'summary',
65+
renderLabel: t('summary'),
66+
rows: 3,
67+
},
68+
];
69+
}
70+
71+
render() {
72+
const { downloading, uploading } = organizationStore;
73+
74+
const loading = downloading > 0 || uploading > 0;
75+
76+
return (
77+
<>
78+
<RestForm
79+
className="container-fluid"
80+
translator={this.observedContext}
81+
store={organizationStore}
82+
fields={this.fields}
83+
onSubmit={this.submitHandler}
84+
/>
85+
{loading && <div>Loading...</div>}
86+
</>
87+
);
88+
}
89+
}

components/Organization/List.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Organization } from '@open-source-bazaar/activityhub-service';
2+
import { computed } from 'mobx';
3+
import { observer } from 'mobx-react';
4+
import { ObservedComponent } from 'mobx-react-helper';
5+
import { Column, RestTable } from 'mobx-restful-table';
6+
import { Container } from 'react-bootstrap';
7+
8+
import organizationStore from '../../models/Organization';
9+
import { i18n, I18nContext } from '../../models/Translation';
10+
import { PageHead } from '../Navigator/PageHead';
11+
12+
@observer
13+
export class OrganizationList extends ObservedComponent<{}, typeof i18n> {
14+
static contextType = I18nContext;
15+
16+
@computed
17+
get columns(): Column<Organization>[] {
18+
const { t } = this.observedContext;
19+
20+
return [
21+
{
22+
key: 'name',
23+
renderHead: t('name'),
24+
renderBody: ({ id, name }) => <a href={`/organization/${id}/editor`}>{name}</a>,
25+
required: true,
26+
minLength: 2,
27+
invalidMessage: t('field_required'),
28+
},
29+
{
30+
key: 'englishName',
31+
renderHead: t('english_name'),
32+
},
33+
{
34+
key: 'url',
35+
renderHead: t('website'),
36+
type: 'url',
37+
renderBody: ({ url }) =>
38+
url && (
39+
<a href={url} target="_blank" rel="noopener noreferrer">
40+
{url}
41+
</a>
42+
),
43+
},
44+
{
45+
key: 'summary',
46+
renderHead: t('summary'),
47+
},
48+
];
49+
}
50+
51+
render() {
52+
const { t } = this.observedContext;
53+
54+
return (
55+
<Container fluid>
56+
<PageHead title={t('organization_list')} />
57+
58+
<RestTable
59+
className="h-100 text-center"
60+
striped
61+
hover
62+
editable
63+
deletable
64+
columns={this.columns}
65+
store={organizationStore}
66+
translator={this.observedContext}
67+
/>
68+
</Container>
69+
);
70+
}
71+
}

0 commit comments

Comments
 (0)