* wip init handle draft class and styling * add draft button * start splitting up listing row into multile files * separate tag links * split location * fix location * separate listing row action buttons * update listing row proptypes to describe listing object * contact via connect to jsx * fix default checked * init draft creation and first publish charge * fix first publish logic and credit charging * handle drafts in dashboard filtering * adjust isDraft bool statement * hide drafts from main listings feed * fix expired and draft bools in listing row * adjust create listing org credits * internally handle drafts * adjust listing row * break down update method * remove unnecessary logic and shorten lines * fix logic again woops * convert input hidden value + submit into one form button submit with corresponding name and value also adds clear message that drafts do not cost credits * handle insufficient org credits on first publish - uses user credits to publish - similar to bump implementation * fix sorting for personal and all orgs * space out some elements * don't spend original users credit for them * add delete buttons and delete_confirm and destroy methods * remove notification removal since listings dont trigger notifications * move draft message and add draft_params to tests * Update classified_listings_controller.rb * update tests * update snapshot * add del tests * add guard preventing free draft publish * fix draft filter * update from master and resolve merge conflict in listing preact * Revert "update from master and resolve merge conflict in listing preact" This reverts commit 0a34fccf334a2ca0902644b486cb26ead6bef664. * update column spec instead of setting and saving * separate two expectations into their own tests * split more tests into single expectations * change to unless bumped_at? instead of if nil * Fix listing draft edge cases and styling * Add title tags to listings pages
77 lines
2.6 KiB
JavaScript
77 lines
2.6 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
import { h } from 'preact';
|
|
import ListingDate from './rowElements/listingDate';
|
|
import Tags from './rowElements/tags';
|
|
import Location from './rowElements/location';
|
|
import ActionButtons from './rowElements/actionButtons';
|
|
|
|
export const ListingRow = ({ listing }) => {
|
|
const bumpedAt = listing.bumped_at ? listing.bumped_at.toString() : null;
|
|
const isExpired =
|
|
bumpedAt && !listing.published
|
|
? (Date.now() - new Date(bumpedAt).getTime()) / (1000 * 60 * 60 * 24) > 30
|
|
: false;
|
|
const isDraft = bumpedAt ? !isExpired && !listing.published : true;
|
|
const listingUrl = listing.published
|
|
? `${listing.category}/${listing.slug}`
|
|
: `${listing.id}/edit`;
|
|
|
|
const expiryDate = listing.expires_at
|
|
? new Date(listing.expires_at.toString()).toLocaleDateString('default', {
|
|
day: '2-digit',
|
|
month: 'short',
|
|
})
|
|
: '';
|
|
|
|
const listingExpiry = expiryDate !== '' ? ` | Expires on: ${expiryDate}` : '';
|
|
|
|
return (
|
|
<div
|
|
className={`dashboard-listing-row ${isDraft ? 'draft' : ''} ${
|
|
isExpired ? 'expired' : ''
|
|
}`}
|
|
>
|
|
{listing.organization_id && (
|
|
<span className="listing-org">{listing.author.name}</span>
|
|
)}
|
|
<a href={listingUrl}>
|
|
<h2>{listing.title + (isExpired ? ' (expired)' : '')}</h2>
|
|
</a>
|
|
<ListingDate
|
|
bumpedAt={listing.bumped_at}
|
|
updatedAt={listing.updated_at}
|
|
/>
|
|
{listingExpiry}
|
|
{listing.location && <Location location={listing.location} />}
|
|
<span className="dashboard-listing-category">
|
|
<a href={`/listings/${listing.category}/`}>{listing.category}</a>
|
|
</span>
|
|
<Tags tagList={listing.tag_list} />
|
|
<ActionButtons
|
|
isDraft={isDraft}
|
|
listingUrl={`${listing.category}/${listing.slug}`}
|
|
editUrl={`/listings/${listing.id}/edit`}
|
|
deleteConfirmUrl={`/listings/${listing.category}/${listing.slug}/delete_confirm`}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
ListingRow.propTypes = {
|
|
listing: PropTypes.PropTypes.shape({
|
|
title: PropTypes.string.isRequired,
|
|
tag_list: PropTypes.arrayOf(PropTypes.string),
|
|
created_at: PropTypes.instanceOf(Date),
|
|
bumped_at: PropTypes.instanceOf(Date),
|
|
updated_at: PropTypes.instanceOf(Date),
|
|
category: PropTypes.string.isRequired,
|
|
id: PropTypes.number.isRequired,
|
|
user_id: PropTypes.number.isRequired,
|
|
slug: PropTypes.string.isRequired,
|
|
organization_id: PropTypes.number,
|
|
location: PropTypes.string,
|
|
expires_at: PropTypes.bool,
|
|
published: PropTypes.bool.isRequired,
|
|
author: PropTypes.object,
|
|
}).isRequired,
|
|
};
|