Skip to content

Commit

Permalink
Delete site and delete site entry functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
maxn990 committed Jun 23, 2024
1 parent 97d7f64 commit 291b222
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 55 deletions.
20 changes: 20 additions & 0 deletions src/api/protectedApiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ export interface ProtectedApiClient {
siteId: number,
request: ReportSiteRequest,
) => Promise<void>;
readonly deleteSite: (siteId: number) => Promise<void>;
readonly deleteSiteEntry: (siteEntryId: number) => Promise<void>;
}

export enum ProtectedApiClientRoutes {
Expand Down Expand Up @@ -280,6 +282,10 @@ export const ParameterizedAdminApiRoutes = {
`api/v1/protected/sites/reject_image/${imageId}?reason=${reason}`,
LOAD_TEMPLATE: (templateName: string): string =>
`api/v1/protected/emailer/load_template/${templateName}`,
DELETE_SITE_ENTRY: (siteEntryId: number): string =>
`/api/v1/protected/sites/delete_entry/${siteEntryId}`,
DELETE_SITE: (siteId: number): string =>
`/api/v1/protected/sites/${siteId}/delete`,
};

const makeReservation = (blockId: number, teamId?: number): Promise<void> => {
Expand Down Expand Up @@ -686,6 +692,18 @@ const reportSiteForIssues = (
).then((res) => res.data);
};

const deleteSiteEntry = (siteEntryId: number): Promise<void> => {
return AppAxiosInstance.delete(
ParameterizedAdminApiRoutes.DELETE_SITE_ENTRY(siteEntryId),
).then((res) => res.data);
};

const deleteSite = (siteId: number): Promise<void> => {
return AppAxiosInstance.post(
ParameterizedAdminApiRoutes.DELETE_SITE(siteId),
).then((res) => res.data);
};

const Client: ProtectedApiClient = Object.freeze({
makeReservation,
completeReservation,
Expand Down Expand Up @@ -743,6 +761,8 @@ const Client: ProtectedApiClient = Object.freeze({
loadEmailTemplateContent,
addTemplate,
reportSiteForIssues,
deleteSiteEntry,
deleteSite,
});

export default Client;
54 changes: 54 additions & 0 deletions src/api/test/protectedApiClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2409,4 +2409,58 @@ describe('Admin Protected Client Routes', () => {
expect(result).toEqual(response);
});
});

describe('delete site', () => {
it('makes the right request', async () => {
const response = '';
nock(BASE_URL)
.post(ParameterizedAdminApiRoutes.DELETE_SITE(100))
.reply(200, response);

const result = await ProtectedApiClient.deleteSite(100);

expect(result).toEqual(response);
});

it('not a valid site', async () => {
const response = 'Site does not exist';

nock(BASE_URL)
.post(ParameterizedAdminApiRoutes.DELETE_SITE(-1))
.reply(400, response);

const result = await ProtectedApiClient.deleteSite(-1).catch(
(err) => err.response.data,
);

expect(result).toEqual(response);
});
});

describe('delete site entry', () => {
it('makes the right request', async () => {
const response = '';
nock(BASE_URL)
.delete(ParameterizedAdminApiRoutes.DELETE_SITE_ENTRY(100))
.reply(200, response);

const result = await ProtectedApiClient.deleteSiteEntry(100);

expect(result).toEqual(response);
});

it('not a valid site', async () => {
const response = 'Site does not exist';

nock(BASE_URL)
.delete(ParameterizedAdminApiRoutes.DELETE_SITE_ENTRY(-1))
.reply(400, response);

const result = await ProtectedApiClient.deleteSiteEntry(-1).catch(
(err) => err.response.data,
);

expect(result).toEqual(response);
});
});
});
2 changes: 1 addition & 1 deletion src/components/forms/editSiteForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Form, Input, Select } from 'antd';
import { Form, Input, Select, Button } from 'antd';
import { FormInstance } from 'antd/es/form';
import { requiredRule, zipCodeRules } from '../../../utils/formRules';
import { EditSiteRequest } from '../ducks/types';
Expand Down
8 changes: 5 additions & 3 deletions src/components/forms/updateSiteForm/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Form, Input, Radio, Row, Space, DatePicker } from 'antd';
import { Form, Input, Radio, Row, Space, DatePicker, Button } from 'antd';
import { FormInstance, Rule } from 'antd/es/form';
import {
BOOL_RADIO_OPTS,
Expand All @@ -19,6 +19,7 @@ import { useTranslation } from 'react-i18next';
import { n } from '../../../utils/stringFormat';
import { site } from '../../../constants';
import moment from 'moment';
import { JSX } from 'react/jsx-runtime';

interface RadioInputProps {
readonly name: string;
Expand Down Expand Up @@ -411,9 +412,10 @@ const UpdateSiteForm: React.FC<UpdateSiteFormProps> = ({
</TitleStack>
</Flex>

<Row justify={'end'}>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<div style={{ marginLeft: 'auto' }}></div>
<SubmitButton htmlType="submit">{t('submit')}</SubmitButton>
</Row>
</div>
</Form>
);
};
Expand Down
133 changes: 87 additions & 46 deletions src/components/siteEntryTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ import {
SiteEntryFields,
} from '../../containers/treePage/ducks/types';
import { Form, Modal, Table, message } from 'antd';
import { EditOutlined } from '@ant-design/icons';
import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
import ProtectedClient from '../../api/protectedApiClient';
import {
booleanToString,
getSEFieldDisplayName,
n,
} from '../../utils/stringFormat';
import { EditButton, StyledClose } from '../themedComponents';
import { EditButton, StyledClose, DeleteButton } from '../themedComponents';
import UpdateSiteForm from '../forms/updateSiteForm';
import { SiteEntriesRequest, UpdateSiteRequest } from '../forms/ducks/types';
import { useTranslation } from 'react-i18next';
import { site } from '../../constants';
import moment from 'moment';

interface SiteEntryTableProps {
readonly siteEntries: SiteEntry[];
readonly getSite: () => void;
siteEntries: SiteEntry[];
getSite: () => void;
}

const SiteEntryTable: React.FC<SiteEntryTableProps> = ({
Expand All @@ -33,66 +33,107 @@ const SiteEntryTable: React.FC<SiteEntryTableProps> = ({
});

const [showEditEntryModal, setShowEditEntryModal] = useState<boolean>(false);
const [editEntryModalData, setEditEntryModalData] = useState<SiteEntry>();
const [editEntryModalData, setEditEntryModalData] = useState<
SiteEntry | undefined
>();

const [editSiteEntryForm] = Form.useForm();

// Columns configuration for the Ant Design Table
const siteEntryTableColumns = Object.values(SiteEntryFields).map(
(field: SiteEntryField) => {
return {
title: getSEFieldDisplayName(field),
dataIndex: field,
key: field,
render: (
val: string | number | boolean,
record: SiteEntry,
): string | JSX.Element => {
if (field !== 'editEntry') {
return val || val === false ? booleanToString(String(val)) : '';
}

return (
<EditButton
type="primary"
onClick={() => {
setShowEditEntryModal(true);
setEditEntryModalData(record);

editSiteEntryForm.setFieldsValue({
...record,
plantingDate: record?.plantingDate
? moment(record?.plantingDate)
: null,
});
}}
>
if (field === 'editEntry') {
return {
title: getSEFieldDisplayName(field),
dataIndex: field,
key: field,
render: (
val: string | number | boolean,
record: SiteEntry,
): JSX.Element => (
<EditButton type="primary" onClick={() => handleEditEntry(record)}>
<EditOutlined />
</EditButton>
);
},
};
),
};
} else if (field === 'deleteEntry') {
return {
title: getSEFieldDisplayName(field),
dataIndex: field,
key: field,
render: (
val: string | number | boolean,
record: SiteEntry,
): JSX.Element => (
<DeleteButton
type="primary"
onClick={() => onDeleteSiteEntry(record.id)}
>
<DeleteOutlined />
</DeleteButton>
),
};
} else {
return {
title: getSEFieldDisplayName(field),
dataIndex: field,
key: field,
render: (val: string | number | boolean): string =>
val || val === false ? booleanToString(String(val)) : '',
};
}
},
);

const onSubmitEditSiteEntry = (request: UpdateSiteRequest) => {
// Function to handle edit button click
const handleEditEntry = (record: SiteEntry) => {
setShowEditEntryModal(true);
setEditEntryModalData(record);

// Set initial form values
editSiteEntryForm.setFieldsValue({
...record,
plantingDate: record?.plantingDate ? moment(record?.plantingDate) : null,
});
};

// Function to handle form submission for editing
const onSubmitEditSiteEntry = (values: UpdateSiteRequest) => {
if (!editEntryModalData) {
return;
}

const entries: SiteEntriesRequest = {
...request,
plantingDate: request.plantingDate?.format('L') || null,
const updatedEntry: SiteEntriesRequest = {
...values,
plantingDate: values.plantingDate?.format('L') || null,
};

ProtectedClient.editSiteEntry(editEntryModalData.id, entries)
ProtectedClient.editSiteEntry(editEntryModalData.id, updatedEntry)
.then(() => {
message.success(t('edit_site_entry.success'));
setShowEditEntryModal(false);
getSite();
getSite(); // Refresh site entries after successful edit
})
.catch((err) => {
message.error(t('edit_site_entry.error', { error: err.response.data }));
});
};

// Function to handle deletion of a site entry
const onDeleteSiteEntry = (siteEntryId: number) => {
ProtectedClient.deleteSiteEntry(siteEntryId)
.then(() => {
message.success('Successfully deleted site entry.');
const updatedSiteEntries = siteEntries.filter(
(entry) => entry.id !== siteEntryId,
);
getSite(); // Refresh site entries after successful deletion
})
.catch((err) =>
message.error(t('edit_site_entry.error', { error: err.response.data })),
);
.catch((err) => {
message.error(
t('delete_site_entry.error', { error: err.response.data }),
);
});
};

return (
Expand All @@ -101,12 +142,12 @@ const SiteEntryTable: React.FC<SiteEntryTableProps> = ({
dataSource={siteEntries}
columns={siteEntryTableColumns}
scroll={{ x: 1300 }}
rowKey={(siteEntry: SiteEntry) => siteEntry.id}
rowKey={(siteEntry: SiteEntry) => siteEntry.id.toString()} // Ensure rowKey is a string
/>

<Modal
title={t('edit_site_entry')}
open={showEditEntryModal}
visible={showEditEntryModal} // Use 'visible' to control visibility
onCancel={() => {
setShowEditEntryModal(false);
editSiteEntryForm.resetFields();
Expand Down
22 changes: 20 additions & 2 deletions src/components/siteFeatures/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React, { useEffect, useState } from 'react';
import { Typography, FormInstance } from 'antd';
import { Typography, FormInstance, Button, Popconfirm, message } from 'antd';
import styled from 'styled-components';
import { SiteProps } from '../../containers/treePage/ducks/types';
import EditSiteForm from '../../components/forms/editSiteForm';
import { getNeighborhoodName, n } from '../../utils/stringFormat';
import { EditSiteRequest } from '../forms/ducks/types';
import { Flex, GreenButton, WhiteButton } from '../themedComponents';
import { Flex, GreenButton, WhiteButton, RedButton } from '../themedComponents';
import TitleStack from '../titleStack';
import { useTranslation } from 'react-i18next';
import { site as website } from '../../constants';
import protectedApiClient from '../../api/protectedApiClient';

const Content = styled(Typography.Text)`
font-size: 15px;
Expand Down Expand Up @@ -46,6 +47,15 @@ const SiteFeatures: React.FC<SiteFeaturesProps> = ({
});
});

const deleteSite = (siteId: number) => {
protectedApiClient
.deleteSite(siteId)
.then(() => window.location.reload())
.catch((err) => {
message.error('Could not delete site: ' + err.response.data);
});
};

return editingFeatures ? (
<>
<EditSiteForm formInstance={editSiteForm} onEdit={onEdit} />
Expand Down Expand Up @@ -94,6 +104,14 @@ const SiteFeatures: React.FC<SiteFeaturesProps> = ({
</Flex>

<Flex justifyContent={'flex-end'}>
<Popconfirm
title="Are you sure you want to delete this site?"
onConfirm={() => deleteSite(site.siteId)}
okText={'Yes'}
cancelText={'No'}
>
<RedButton>Delete Site</RedButton>
</Popconfirm>
<GreenButton
onClick={() => {
setEditingFeatures(true);
Expand Down
Loading

0 comments on commit 291b222

Please sign in to comment.