Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: share resource #262

Merged
merged 4 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/api_client/lib/src/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,27 @@ class ApiClient {
});
}

/// Returns the score share url for the score for the specified [userId].
String shareScoreUrl(String userId) {
return _base.replace(
path: '/public/share/score',
queryParameters: {
'userId': userId,
},
).toString();
}

/// Returns the word share url for the specified [sectionId] and [wordId].
String shareWordUrl(String sectionId, String wordId) {
return _base.replace(
path: '/public/share/word',
queryParameters: {
'sectionId': sectionId,
'wordId': wordId,
},
).toString();
}

/// Sends a PATCH request to the specified [path] with the given [body].
Future<http.Response> patch(
String path, {
Expand Down
1 change: 1 addition & 0 deletions packages/api_client/lib/src/resources/resources.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export 'crossword_resource.dart';
export 'leaderboard_resource.dart';
export 'share_resource.dart';
88 changes: 88 additions & 0 deletions packages/api_client/lib/src/resources/share_resource.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:api_client/api_client.dart';

/// {@template crossword_resource}
/// An api resource for the public sharing API.
/// {@endtemplate}
class ShareResource {
/// {@macro crossword_resource}
ShareResource({
required ApiClient apiClient,
}) : _apiClient = apiClient;

final ApiClient _apiClient;

final _tweetContent = 'Check out my score at IOCrossword #GoogleIO!';

String _twitterShareUrl(String text) =>
'https://twitter.com/intent/tweet?text=$text';

String _facebookShareUrl(String shareUrl) =>
'https://www.facebook.com/sharer.php?u=$shareUrl';

String _instagramShareUrl(String shareUrl) =>
'https://www.instagram.com/?url=$shareUrl';

String _linkedinShareUrl(String shareUrl) =>
'https://www.linkedin.com/sharing/share-offsite/?url=$shareUrl';

// TODO(any): Consider relying on built-in Uri encoding.
// https://very-good-ventures-team.monday.com/boards/6004820050/pulses/6444093330
String _encode(List<String> content) =>
content.join('%0a').replaceAll(' ', '%20').replaceAll('#', '%23');
alestiago marked this conversation as resolved.
Show resolved Hide resolved

/// Returns the url to share a facebook post for the score.
String facebookShareScoreUrl(String userId) {
final shareUrl = _apiClient.shareScoreUrl(userId);
return _facebookShareUrl(shareUrl);
}

/// Returns the url to share a twitter post for the score.
String twitterShareScoreUrl(String userId) {
final shareUrl = _apiClient.shareScoreUrl(userId);
final content = [
_tweetContent,
shareUrl,
];
return _twitterShareUrl(_encode(content));
}

/// Returns the url to share a instagram post for the score.
String instagramShareScoreUrl(String userId) {
final shareUrl = _apiClient.shareScoreUrl(userId);
return _instagramShareUrl(shareUrl);
}

/// Returns the url to share a linkedin post for the score.
String linkedinShareScoreUrl(String userId) {
final shareUrl = _apiClient.shareScoreUrl(userId);
return _linkedinShareUrl(shareUrl);
}

/// Returns the url to share a facebook post for a word.
String facebookShareWordUrl(String sectionId, String wordId) {
final shareUrl = _apiClient.shareWordUrl(sectionId, wordId);
return _facebookShareUrl(shareUrl);
}

/// Returns the url to share a twitter post for a word.
String twitterShareWordUrl(String sectionId, String wordId) {
final shareUrl = _apiClient.shareWordUrl(sectionId, wordId);
final content = [
_tweetContent,
shareUrl,
];
return _twitterShareUrl(_encode(content));
}

/// Returns the url to share a instagram post for a word.
String instagramShareWordUrl(String sectionId, String wordId) {
final shareUrl = _apiClient.shareWordUrl(sectionId, wordId);
return _instagramShareUrl(shareUrl);
}

/// Returns the url to share a linkedin post for a word.
String linkedinShareWordUrl(String sectionId, String wordId) {
final shareUrl = _apiClient.shareWordUrl(sectionId, wordId);
return _linkedinShareUrl(shareUrl);
}
}
20 changes: 20 additions & 0 deletions packages/api_client/test/src/api_client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,26 @@ void main() {
});
});

group('shareScoreUrl', () {
test('returns the correct url', () {
expect(
subject.shareScoreUrl('id'),
equals('http://baseurl.com/public/share/score?userId=id'),
);
});
});

group('shareScoreUrl', () {
test('returns the correct url', () {
expect(
subject.shareWordUrl('id', 'wordId'),
equals(
'http://baseurl.com/public/share/word?sectionId=id&wordId=wordId',
),
);
});
});

group('get', () {
test('returns the response', () async {
final response = await subject.get('/');
Expand Down
86 changes: 86 additions & 0 deletions packages/api_client/test/src/resources/share_resource_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import 'package:api_client/api_client.dart';
import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';

class _MockApiClient extends Mock implements ApiClient {}

void main() {
group('ShareResource', () {
late ApiClient apiClient;
late ShareResource resource;

setUp(() {
apiClient = _MockApiClient();

when(() => apiClient.shareWordUrl(any(), any())).thenReturn('wordUrl');
when(() => apiClient.shareScoreUrl(any())).thenReturn('scoreUrl');

resource = ShareResource(
apiClient: apiClient,
);
});

test('can be instantiated', () {
expect(
resource,
isNotNull,
);
});

test('facebookShareScoreUrl returns the correct url', () {
expect(
resource.facebookShareScoreUrl('id'),
contains('scoreUrl'),
);
});

test('facebookShareScoreUrl returns the correct url', () {
expect(
resource.facebookShareWordUrl('sectionId', 'wordId'),
contains('wordUrl'),
);
});

test('instagramShareScoreUrl returns the correct url', () {
expect(
resource.instagramShareScoreUrl('id'),
contains('scoreUrl'),
);
});

test('instagramShareWordUrl returns the correct url', () {
expect(
resource.instagramShareWordUrl('sectionId', 'wordId'),
contains('wordUrl'),
);
});

test('twitterShareScoreUrl returns the correct url', () {
expect(
resource.twitterShareScoreUrl('id'),
contains('scoreUrl'),
);
});

test('twitterShareWordUrl returns the correct url', () {
expect(
resource.twitterShareWordUrl('sectionId', 'wordId'),
contains('wordUrl'),
);
});

test('linkedinShareScoreUrl returns the correct url', () {
expect(
resource.linkedinShareScoreUrl('id'),
contains('scoreUrl'),
);
});

test('linkedinShareWordUrl returns the correct url', () {
expect(
resource.linkedinShareWordUrl('sectionId', 'wordId'),
contains('wordUrl'),
);
});
});
}
Loading