diff --git a/app/soapbox/actions/statuses.js b/app/soapbox/actions/statuses.js
index 5b65349b7..440d4150e 100644
--- a/app/soapbox/actions/statuses.js
+++ b/app/soapbox/actions/statuses.js
@@ -3,6 +3,7 @@ import { deleteFromTimelines } from './timelines';
import { importFetchedStatus, importFetchedStatuses } from './importer';
import { openModal } from './modal';
import { isLoggedIn } from 'soapbox/utils/auth';
+import { shouldHaveCard } from 'soapbox/utils/status';
export const STATUS_CREATE_REQUEST = 'STATUS_CREATE_REQUEST';
export const STATUS_CREATE_SUCCESS = 'STATUS_CREATE_SUCCESS';
@@ -44,8 +45,31 @@ export function createStatus(params, idempotencyKey) {
return api(getState).post('/api/v1/statuses', params, {
headers: { 'Idempotency-Key': idempotencyKey },
}).then(({ data: status }) => {
+ // The backend might still be processing the rich media attachment
+ if (!status.card && shouldHaveCard(status)) {
+ status.expectsCard = true;
+ }
+
dispatch(importFetchedStatus(status, idempotencyKey));
dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey });
+
+ // Poll the backend for the updated card
+ if (status.expectsCard) {
+ const delay = 1000;
+
+ const poll = (retries = 5) => {
+ api(getState).get(`/api/v1/statuses/${status.id}`).then(response => {
+ if (response.data && response.data.card) {
+ dispatch(importFetchedStatus(response.data));
+ } else if (retries > 0 && response.status === 200) {
+ setTimeout(() => poll(retries - 1), delay);
+ }
+ }).catch(console.error);
+ };
+
+ setTimeout(() => poll(), delay);
+ }
+
return status;
}).catch(error => {
dispatch({ type: STATUS_CREATE_FAIL, error, params, idempotencyKey });
diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js
index de7a330ca..ff7f23f52 100644
--- a/app/soapbox/components/status.js
+++ b/app/soapbox/components/status.js
@@ -19,6 +19,7 @@ import Icon from 'soapbox/components/icon';
import { Link, NavLink } from 'react-router-dom';
import { getDomain } from 'soapbox/utils/accounts';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
+import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder_card';
// We use the component (and not the container) since we do not want
// to use the progress bar to show download progress
@@ -465,6 +466,10 @@ class Status extends ImmutablePureComponent {
defaultWidth={this.props.cachedMediaWidth}
/>
);
+ } else if (status.get('expectsCard', false)) {
+ media = (
+
+ {generateText(randomIntFromInterval(5, 75))} +
+ + {generateText(randomIntFromInterval(5, 15))} + +{trim(card.get('description') || '', maxDescription)}